388 lines
42 KiB
HTML
388 lines
42 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
|
<html>
|
|
<head>
|
|
<title>Case-Insensitive Filenames</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 'Case-Insensitive Filenames' 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#3">Chapter 3: The Operating System</a></li><li><b>Case-Insensitive Filenames</b></li></ul><p class="purpose">On some of the Unix-derived file systems on which Inform runs, filenames are case-sensitive, so that FISH and fish might be different files. This makes extension files, installed by the user, prone to being missed. The code in this section provides a routine to carry out file opening as if filenames are case-insensitive, and is used only for extensions.</p>
|
|
|
|
<ul class="toc"><li><a href="#SP3">§3. The routine</a></li><li><a href="#SP3_1">§3.1. Looking for case-insensitive matches instead</a></li><li><a href="#SP3_3">§3.3. Allocation and deallocation</a></li><li><a href="#SP3_6">§3.6. Pathname hacking</a></li><li><a href="#SP4">§4. Counting matches</a></li><li><a href="#SP5">§5. Non-POSIX tail</a></li></ul><hr class="tocbar">
|
|
|
|
<p class="inwebparagraph"><a id="SP1"></a><b>§1. </b>This section contains a single utility routine, contributed by Adam
|
|
Thornton: a specialised, case-insensitive form of <code class="display"><span class="extract">fopen()</span></code>. It is specialised
|
|
in that it is designed for opening extensions, where the file path will be
|
|
case-correct up to the last two components of the path (the leafname and the
|
|
immediately containing directory), but where the casing may be wrong in those
|
|
last two components.
|
|
</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP2"></a><b>§2. </b>If the exact filename or extension directory (case-correct) exists,
|
|
<code class="display"><span class="extract">CIFilingSystem::fopen()</span></code> will choose it to open. If not, it will
|
|
use <code class="display"><span class="extract">strcasecmp()</span></code> to find a file or directory with the same name but
|
|
differing in case and use it instead. If it finds exactly one candidate file,
|
|
it will then attempt to <code class="display"><span class="extract">fopen()</span></code> it and return the result.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">If <code class="display"><span class="extract">CIFilingSystem::fopen()</span></code> succeeds, it returns a <code class="display"><span class="extract">FILE *</span></code>
|
|
(passed back to it from the underlying <code class="display"><span class="extract">fopen()</span></code>). If
|
|
<code class="display"><span class="extract">CIFilingSystem::fopen()</span></code> fails, it returns <code class="display"><span class="extract">NULL</span></code>, and
|
|
<code class="display"><span class="extract">errno</span></code> is set accordingly:
|
|
</p>
|
|
|
|
<ul class="items"><li>(a) If no suitable file was found, <code class="display"><span class="extract">errno</span></code> is set to <code class="display"><span class="extract">ENOENT</span></code>.
|
|
</li><li>(b) If more than one possibility was found, but none of them exactly match
|
|
the supplied case, <code class="display"><span class="extract">errno</span></code> is set to <code class="display"><span class="extract">EBADF</span></code>.
|
|
</li><li>(c) Note that if multiple directories which match case-insensitively are
|
|
found, but none is an exact match, <code class="display"><span class="extract">EBADF</span></code> will be set regardless of the
|
|
contents of the directories.
|
|
</li><li>(d) If <code class="display"><span class="extract">CIFilingSystem::fopen()</span></code> fails during its allocation of
|
|
space to hold its intermediate strings for comparison, or for its various
|
|
data structures, <code class="display"><span class="extract">errno</span></code> is set to <code class="display"><span class="extract">ENOMEM</span></code>.
|
|
</li><li>(e) If an unambiguous filename is found but the <code class="display"><span class="extract">fopen()</span></code> fails, <code class="display"><span class="extract">errno</span></code> is
|
|
left at whatever value the underlying <code class="display"><span class="extract">fopen()</span></code> set it to.
|
|
</li></ul>
|
|
<p class="inwebparagraph"><a id="SP3"></a><b>§3. The routine. </b>The routine is available only on POSIX platforms where <code class="display"><span class="extract">PLATFORM_POSIX</span></code>
|
|
is defined (see "Platform-Specific Definitions"). In practice this means
|
|
everywhere except Windows, but all Windows file systems are case-preserving
|
|
and case-insensitive in any case.
|
|
</p>
|
|
|
|
<p class="inwebparagraph">Briefly, we try to get the extension directory name right first, by looking
|
|
for the given casing, then if that fails, for a unique alternative with
|
|
different casing; and then repeat within that directory for the extension
|
|
file itself.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">FILE</span><span class="plain"> *</span><span class="functiontext"><a href="#SP5">CIFilingSystem::fopen</a></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">path</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">mode</span><span class="plain">) {</span>
|
|
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">topdirpath</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">, *</span><span class="identifier">ciextdirpath</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">, *</span><span class="identifier">cistring</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">, *</span><span class="identifier">ciextname</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">workstring</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">, *</span><span class="identifier">workstring2</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
<span class="identifier">DIR</span><span class="plain"> *</span><span class="identifier">topdir</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">, *</span><span class="identifier">extdir</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span><span class="reserved">FILE</span><span class="plain"> *</span><span class="identifier">handle</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="comment"> for efficiency's sake, though it's logically equivalent, we try...</span>
|
|
<span class="identifier">handle</span><span class="plain"> = </span><span class="identifier">fopen</span><span class="plain">(</span><span class="identifier">path</span><span class="plain">, </span><span class="identifier">mode</span><span class="plain">); </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">handle</span><span class="plain">) </span><<span class="cwebmacro">Happy ending to ci-fopen</span> <span class="cwebmacronumber">3.4</span>><span class="plain">;</span>
|
|
|
|
<<span class="cwebmacro">Find the length of the path, giving an error if it is empty or NULL</span> <span class="cwebmacronumber">3.6</span>><span class="plain">;</span>
|
|
<<span class="cwebmacro">Allocate memory for strings large enough to hold any subpath of the path</span> <span class="cwebmacronumber">3.3</span>><span class="plain">;</span>
|
|
<<span class="cwebmacro">Parse the path to break it into topdir path, extension directory and leafname</span> <span class="cwebmacronumber">3.7</span>><span class="plain">;</span>
|
|
|
|
<span class="identifier">topdir</span><span class="plain"> = </span><span class="identifier">opendir</span><span class="plain">(</span><span class="identifier">topdirpath</span><span class="plain">); </span><span class="comment"> whose pathname is assumed case-correct...</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">topdir</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><<span class="cwebmacro">Sad ending to ci-fopen</span> <span class="cwebmacronumber">3.5</span>><span class="plain">; </span> <span class="comment"> ...so that failure is fatal; <code class="display"><span class="extract">errno</span></code> is set by <code class="display"><span class="extract">opendir</span></code></span>
|
|
|
|
<span class="identifier">sprintf</span><span class="plain">(</span><span class="identifier">workstring</span><span class="plain">, </span><span class="string">"%s%c%s"</span><span class="plain">, </span><span class="identifier">topdirpath</span><span class="plain">, </span><span class="constant">FOLDER_SEPARATOR</span><span class="plain">, </span><span class="identifier">ciextdirpath</span><span class="plain">);</span>
|
|
<span class="identifier">extdir</span><span class="plain"> = </span><span class="identifier">opendir</span><span class="plain">(</span><span class="identifier">workstring</span><span class="plain">); </span><span class="comment"> try with supplied extension directory name</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">extdir</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><<span class="cwebmacro">Try to find a unique insensitively matching directory name in topdir</span> <span class="cwebmacronumber">3.1</span>>
|
|
<span class="reserved">else</span><span class="plain"> </span><span class="identifier">strcpy</span><span class="plain">(</span><span class="identifier">cistring</span><span class="plain">, </span><span class="identifier">workstring</span><span class="plain">);</span>
|
|
|
|
<span class="identifier">sprintf</span><span class="plain">(</span><span class="identifier">workstring</span><span class="plain">, </span><span class="string">"%s%c%s"</span><span class="plain">, </span><span class="identifier">cistring</span><span class="plain">, </span><span class="constant">FOLDER_SEPARATOR</span><span class="plain">, </span><span class="identifier">ciextname</span><span class="plain">);</span>
|
|
<span class="identifier">handle</span><span class="plain"> = </span><span class="identifier">fopen</span><span class="plain">(</span><span class="identifier">workstring</span><span class="plain">, </span><span class="identifier">mode</span><span class="plain">); </span><span class="comment"> try with supplied name</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">handle</span><span class="plain">) </span><<span class="cwebmacro">Happy ending to ci-fopen</span> <span class="cwebmacronumber">3.4</span>><span class="plain">;</span>
|
|
|
|
<<span class="cwebmacro">Try to find a unique insensitively matching entry in extdir</span> <span class="cwebmacronumber">3.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_POSIX is defined.</p>
|
|
|
|
<p class="endnote">The function CIFilingSystem::fopen is used in <a href="#SP5">§5</a>, Filenames (<a href="3-fln.html#SP10">§10</a>).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP3_1"></a><b>§3.1. Looking for case-insensitive matches instead. </b>We emerge from the following only in the happy case where a unique matching
|
|
directory name can be found.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Try to find a unique insensitively matching directory name in topdir</span> <span class="cwebmacronumber">3.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rc</span><span class="plain"> = </span><span class="functiontext"><a href="#SP4">CIFilingSystem::match_in_directory</a></span><span class="plain">(</span><span class="identifier">topdir</span><span class="plain">, </span><span class="identifier">ciextdirpath</span><span class="plain">, </span><span class="identifier">workstring</span><span class="plain">);</span>
|
|
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">rc</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">0</span><span class="plain">:</span>
|
|
<span class="identifier">errno</span><span class="plain"> = </span><span class="identifier">ENOENT</span><span class="plain">; </span><<span class="cwebmacro">Sad ending to ci-fopen</span> <span class="cwebmacronumber">3.5</span>><span class="plain">;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">1</span><span class="plain">:</span>
|
|
<span class="identifier">sprintf</span><span class="plain">(</span><span class="identifier">cistring</span><span class="plain">, </span><span class="string">"%s%c%s"</span><span class="plain">, </span><span class="identifier">topdirpath</span><span class="plain">, </span><span class="constant">FOLDER_SEPARATOR</span><span class="plain">, </span><span class="identifier">workstring</span><span class="plain">);</span>
|
|
<span class="identifier">extdir</span><span class="plain"> = </span><span class="identifier">opendir</span><span class="plain">(</span><span class="identifier">cistring</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">extdir</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
|
<span class="identifier">errno</span><span class="plain"> = </span><span class="identifier">ENOENT</span><span class="plain">; </span><<span class="cwebmacro">Sad ending to ci-fopen</span> <span class="cwebmacronumber">3.5</span>><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">break</span><span class="plain">;</span>
|
|
<span class="identifier">default:</span>
|
|
<span class="identifier">errno</span><span class="plain"> = </span><span class="identifier">EBADF</span><span class="plain">; </span><<span class="cwebmacro">Sad ending to ci-fopen</span> <span class="cwebmacronumber">3.5</span>><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP3">§3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP3_2"></a><b>§3.2. </b>More or less the same, but we never emerge at all: all cases of the switch
|
|
return from the function.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Try to find a unique insensitively matching entry in extdir</span> <span class="cwebmacronumber">3.2</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rc</span><span class="plain"> = </span><span class="functiontext"><a href="#SP4">CIFilingSystem::match_in_directory</a></span><span class="plain">(</span><span class="identifier">extdir</span><span class="plain">, </span><span class="identifier">ciextname</span><span class="plain">, </span><span class="identifier">workstring</span><span class="plain">);</span>
|
|
|
|
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">rc</span><span class="plain">) {</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">0</span><span class="plain">:</span>
|
|
<span class="identifier">errno</span><span class="plain"> = </span><span class="identifier">ENOENT</span><span class="plain">; </span><<span class="cwebmacro">Sad ending to ci-fopen</span> <span class="cwebmacronumber">3.5</span>><span class="plain">;</span>
|
|
<span class="reserved">case</span><span class="plain"> </span><span class="constant">1</span><span class="plain">:</span>
|
|
<span class="identifier">sprintf</span><span class="plain">(</span><span class="identifier">workstring2</span><span class="plain">, </span><span class="string">"%s%c%s"</span><span class="plain">, </span><span class="identifier">cistring</span><span class="plain">, </span><span class="constant">FOLDER_SEPARATOR</span><span class="plain">, </span><span class="identifier">workstring</span><span class="plain">);</span>
|
|
<span class="identifier">workstring2</span><span class="plain">[</span><span class="identifier">length</span><span class="plain">] = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="identifier">handle</span><span class="plain"> = </span><span class="identifier">fopen</span><span class="plain">(</span><span class="identifier">workstring2</span><span class="plain">, </span><span class="identifier">mode</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">handle</span><span class="plain">) </span><<span class="cwebmacro">Happy ending to ci-fopen</span> <span class="cwebmacronumber">3.4</span>><span class="plain">;</span>
|
|
<span class="identifier">errno</span><span class="plain"> = </span><span class="identifier">ENOENT</span><span class="plain">; </span><<span class="cwebmacro">Sad ending to ci-fopen</span> <span class="cwebmacronumber">3.5</span>><span class="plain">;</span>
|
|
<span class="identifier">default:</span>
|
|
<span class="identifier">errno</span><span class="plain"> = </span><span class="identifier">EBADF</span><span class="plain">; </span><<span class="cwebmacro">Sad ending to ci-fopen</span> <span class="cwebmacronumber">3.5</span>><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP3">§3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP3_3"></a><b>§3.3. Allocation and deallocation. </b>We use six strings to hold full or partial pathnames.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Allocate memory for strings large enough to hold any subpath of the path</span> <span class="cwebmacronumber">3.3</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">workstring</span><span class="plain"> = </span><span class="identifier">calloc</span><span class="plain">(</span><span class="identifier">length</span><span class="plain">+1, </span><span class="reserved">sizeof</span><span class="plain">(</span><span class="reserved">char</span><span class="plain">));</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">workstring</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) { </span><span class="identifier">errno</span><span class="plain"> = </span><span class="identifier">ENOMEM</span><span class="plain">; </span><<span class="cwebmacro">Sad ending to ci-fopen</span> <span class="cwebmacronumber">3.5</span>><span class="plain">; }</span>
|
|
<span class="identifier">workstring2</span><span class="plain"> = </span><span class="identifier">calloc</span><span class="plain">(</span><span class="identifier">length</span><span class="plain">+1, </span><span class="reserved">sizeof</span><span class="plain">(</span><span class="reserved">char</span><span class="plain">));</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">workstring2</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) { </span><span class="identifier">errno</span><span class="plain"> = </span><span class="identifier">ENOMEM</span><span class="plain">; </span><<span class="cwebmacro">Sad ending to ci-fopen</span> <span class="cwebmacronumber">3.5</span>><span class="plain">; }</span>
|
|
<span class="identifier">topdirpath</span><span class="plain"> = </span><span class="identifier">calloc</span><span class="plain">(</span><span class="identifier">length</span><span class="plain">+1, </span><span class="reserved">sizeof</span><span class="plain">(</span><span class="reserved">char</span><span class="plain">));</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">topdirpath</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) { </span><span class="identifier">errno</span><span class="plain"> = </span><span class="identifier">ENOMEM</span><span class="plain">; </span><<span class="cwebmacro">Sad ending to ci-fopen</span> <span class="cwebmacronumber">3.5</span>><span class="plain">; }</span>
|
|
<span class="identifier">ciextdirpath</span><span class="plain"> = </span><span class="identifier">calloc</span><span class="plain">(</span><span class="identifier">length</span><span class="plain">+1, </span><span class="reserved">sizeof</span><span class="plain">(</span><span class="reserved">char</span><span class="plain">));</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ciextdirpath</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) { </span><span class="identifier">errno</span><span class="plain"> = </span><span class="identifier">ENOMEM</span><span class="plain">; </span><<span class="cwebmacro">Sad ending to ci-fopen</span> <span class="cwebmacronumber">3.5</span>><span class="plain">; }</span>
|
|
<span class="identifier">cistring</span><span class="plain"> = </span><span class="identifier">calloc</span><span class="plain">(</span><span class="identifier">length</span><span class="plain">+1, </span><span class="reserved">sizeof</span><span class="plain">(</span><span class="reserved">char</span><span class="plain">));</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">cistring</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) { </span><span class="identifier">errno</span><span class="plain"> = </span><span class="identifier">ENOMEM</span><span class="plain">; </span><<span class="cwebmacro">Sad ending to ci-fopen</span> <span class="cwebmacronumber">3.5</span>><span class="plain">; }</span>
|
|
<span class="identifier">ciextname</span><span class="plain"> = </span><span class="identifier">calloc</span><span class="plain">(</span><span class="identifier">length</span><span class="plain">+1, </span><span class="reserved">sizeof</span><span class="plain">(</span><span class="reserved">char</span><span class="plain">));</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ciextname</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) { </span><span class="identifier">errno</span><span class="plain"> = </span><span class="identifier">ENOMEM</span><span class="plain">; </span><<span class="cwebmacro">Sad ending to ci-fopen</span> <span class="cwebmacronumber">3.5</span>><span class="plain">; }</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP3">§3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP3_4"></a><b>§3.4. </b>If we are successful, we return a valid file handle...
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Happy ending to ci-fopen</span> <span class="cwebmacronumber">3.4</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<<span class="cwebmacro">Prepare to exit ci-fopen cleanly</span> <span class="cwebmacronumber">3.4.1</span>><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">handle</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP3">§3</a> (twice), <a href="#SP3_2">§3.2</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP3_5"></a><b>§3.5. </b>...and otherwise <code class="display"><span class="extract">NULL</span></code>, having already set <code class="display"><span class="extract">errno</span></code> with the reason why.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Sad ending to ci-fopen</span> <span class="cwebmacronumber">3.5</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<<span class="cwebmacro">Prepare to exit ci-fopen cleanly</span> <span class="cwebmacronumber">3.4.1</span>><span class="plain">;</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP3">§3</a>, <a href="#SP3_1">§3.1</a> (three times), <a href="#SP3_2">§3.2</a> (three times), <a href="#SP3_3">§3.3</a> (6 times).</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP3_4_1"></a><b>§3.4.1. </b><code class="display">
|
|
<<span class="cwebmacrodefn">Prepare to exit ci-fopen cleanly</span> <span class="cwebmacronumber">3.4.1</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">workstring</span><span class="plain">) </span><span class="identifier">free</span><span class="plain">(</span><span class="identifier">workstring</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">workstring2</span><span class="plain">) </span><span class="identifier">free</span><span class="plain">(</span><span class="identifier">workstring2</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">topdirpath</span><span class="plain">) </span><span class="identifier">free</span><span class="plain">(</span><span class="identifier">topdirpath</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ciextdirpath</span><span class="plain">) </span><span class="identifier">free</span><span class="plain">(</span><span class="identifier">ciextdirpath</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">cistring</span><span class="plain">) </span><span class="identifier">free</span><span class="plain">(</span><span class="identifier">cistring</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">ciextname</span><span class="plain">) </span><span class="identifier">free</span><span class="plain">(</span><span class="identifier">ciextname</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">topdir</span><span class="plain">) </span><span class="identifier">closedir</span><span class="plain">(</span><span class="identifier">topdir</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">extdir</span><span class="plain">) </span><span class="identifier">closedir</span><span class="plain">(</span><span class="identifier">extdir</span><span class="plain">);</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP3_4">§3.4</a>, <a href="#SP3_5">§3.5</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP3_6"></a><b>§3.6. Pathname hacking. </b></p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Find the length of the path, giving an error if it is empty or NULL</span> <span class="cwebmacronumber">3.6</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="identifier">length</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">path</span><span class="plain">) </span><span class="identifier">length</span><span class="plain"> = (</span><span class="identifier">size_t</span><span class="plain">) </span><span class="identifier">strlen</span><span class="plain">(</span><span class="identifier">path</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">length</span><span class="plain"> < </span><span class="constant">1</span><span class="plain">) { </span><span class="identifier">errno</span><span class="plain"> = </span><span class="identifier">ENOENT</span><span class="plain">; </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">NULL</span><span class="plain">; }</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP3">§3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP3_7"></a><b>§3.7. </b>And here we break up a pathname like
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="plain">/Users/bobama/Library/Inform/Extensions/Hillary Clinton/Health Care.i7x</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph">into three components:
|
|
</p>
|
|
|
|
<ul class="items"><li>(a) <code class="display"><span class="extract">topdirpath</span></code> is <code class="display"><span class="extract">/Users/bobama/Library/Inform/Extensions</span></code>, and its casing is correct.
|
|
</li><li>(b) <code class="display"><span class="extract">ciextdirpath</span></code> is <code class="display"><span class="extract">Hillary Clinton</span></code>, but its casing may not be correct.
|
|
</li><li>(c) <code class="display"><span class="extract">ciextname</span></code> is <code class="display"><span class="extract">Health Care.i7x</span></code>, but its casing may not be correct.
|
|
</li></ul>
|
|
<p class="inwebparagraph">The contents of <code class="display"><span class="extract">workstring</span></code> are not significant afterwards.
|
|
</p>
|
|
|
|
|
|
<p class="macrodefinition"><code class="display">
|
|
<<span class="cwebmacrodefn">Parse the path to break it into topdir path, extension directory and leafname</span> <span class="cwebmacronumber">3.7</span>> =
|
|
</code></p>
|
|
|
|
|
|
<pre class="displaydefn">
|
|
<span class="reserved">char</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">extdirindex</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">, </span><span class="identifier">extindex</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">, </span><span class="identifier">namelen</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">, </span><span class="identifier">dirlen</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">p</span><span class="plain"> = </span><span class="identifier">strrchr</span><span class="plain">(</span><span class="identifier">path</span><span class="plain">, </span><span class="constant">FOLDER_SEPARATOR</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">p</span><span class="plain">) {</span>
|
|
<span class="identifier">extindex</span><span class="plain"> = (</span><span class="identifier">size_t</span><span class="plain">) (</span><span class="identifier">p</span><span class="plain"> - </span><span class="identifier">path</span><span class="plain">);</span>
|
|
<span class="identifier">namelen</span><span class="plain"> = </span><span class="identifier">length</span><span class="plain"> - </span><span class="identifier">extindex</span><span class="plain"> - </span><span class="constant">1</span><span class="plain">;</span>
|
|
<span class="identifier">strncpy</span><span class="plain">(</span><span class="identifier">ciextname</span><span class="plain">, </span><span class="identifier">path</span><span class="plain"> + </span><span class="identifier">extindex</span><span class="plain"> + </span><span class="constant">1</span><span class="plain">, </span><span class="identifier">namelen</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">ciextname</span><span class="plain">[</span><span class="identifier">namelen</span><span class="plain">] = </span><span class="constant">0</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">strncpy</span><span class="plain">(</span><span class="identifier">workstring</span><span class="plain">, </span><span class="identifier">path</span><span class="plain">, </span><span class="identifier">extindex</span><span class="plain">);</span>
|
|
<span class="identifier">workstring</span><span class="plain">[</span><span class="identifier">extindex</span><span class="plain">] = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="identifier">p</span><span class="plain"> = </span><span class="identifier">strrchr</span><span class="plain">(</span><span class="identifier">workstring</span><span class="plain">, </span><span class="constant">FOLDER_SEPARATOR</span><span class="plain">);</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">p</span><span class="plain">) {</span>
|
|
<span class="identifier">extdirindex</span><span class="plain"> = (</span><span class="identifier">size_t</span><span class="plain">) (</span><span class="identifier">p</span><span class="plain"> - </span><span class="identifier">workstring</span><span class="plain">);</span>
|
|
<span class="identifier">strncpy</span><span class="plain">(</span><span class="identifier">topdirpath</span><span class="plain">, </span><span class="identifier">path</span><span class="plain">, </span><span class="identifier">extdirindex</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="identifier">topdirpath</span><span class="plain">[</span><span class="identifier">extdirindex</span><span class="plain">] = </span><span class="constant">0</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">dirlen</span><span class="plain"> = </span><span class="identifier">extindex</span><span class="plain"> - </span><span class="identifier">extdirindex</span><span class="plain">;</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">dirlen</span><span class="plain"> > </span><span class="constant">0</span><span class="plain">) </span><span class="identifier">dirlen</span><span class="plain"> -= </span><span class="constant">1</span><span class="plain">;</span>
|
|
<span class="identifier">strncpy</span><span class="plain">(</span><span class="identifier">ciextdirpath</span><span class="plain">, </span><span class="identifier">path</span><span class="plain"> + </span><span class="identifier">extdirindex</span><span class="plain"> + </span><span class="constant">1</span><span class="plain">, </span><span class="identifier">dirlen</span><span class="plain">);</span>
|
|
<span class="identifier">ciextdirpath</span><span class="plain">[</span><span class="identifier">dirlen</span><span class="plain">] = </span><span class="constant">0</span><span class="plain">;</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="endnote">This code is used in <a href="#SP3">§3</a>.</p>
|
|
|
|
<p class="inwebparagraph"><a id="SP4"></a><b>§4. Counting matches. </b>We count the number of names within the directory which case-insensitively
|
|
match against <code class="display"><span class="extract">name</span></code>, and copy the last which matches into <code class="display"><span class="extract">last_match</span></code>.
|
|
This must be at least as long as <code class="display"><span class="extract">name</span></code>. (We ought to be just a little careful
|
|
in case of improbable cases where the matched name contains a different
|
|
number of characters from <code class="display"><span class="extract">name</span></code>, for instance because on a strict reading
|
|
of Unicode "SS" is casing-equivalent to the eszet, but it's unlikely
|
|
that many contemporary implementations of <code class="display"><span class="extract">strcasecmp</span></code> are aware of this,
|
|
and in any case the code above contains much larger buffers than needed.)
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">CIFilingSystem::match_in_directory<button class="popup" onclick="togglePopup('usagePopup220')">...<span class="popuptext" id="usagePopup220">Usage of <b>CIFilingSystem::match_in_directory</b>:<br><a href="#SP3_1">§3.1</a>, <a href="#SP3_2">§3.2</a></span></button></span><span class="plain">(</span><span class="reserved">void</span><span class="plain"> *</span><span class="identifier">vd</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">char</span><span class="plain"> *</span><span class="identifier">last_match</span><span class="plain">) {</span>
|
|
<span class="identifier">DIR</span><span class="plain"> *</span><span class="identifier">d</span><span class="plain"> = (</span><span class="identifier">DIR</span><span class="plain"> *) </span><span class="identifier">vd</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">dirp</span><span class="plain">;</span>
|
|
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">rc</span><span class="plain"> = </span><span class="constant">0</span><span class="plain">;</span>
|
|
|
|
<span class="identifier">last_match</span><span class="plain">[0] = </span><span class="constant">0</span><span class="plain">;</span>
|
|
<span class="reserved">while</span><span class="plain"> ((</span><span class="identifier">dirp</span><span class="plain"> = </span><span class="identifier">readdir</span><span class="plain">(</span><span class="identifier">d</span><span class="plain">)) != </span><span class="identifier">NULL</span><span class="plain">) {</span>
|
|
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">strcasecmp</span><span class="plain">(</span><span class="identifier">name</span><span class="plain">, </span><span class="identifier">dirp</span><span class="plain">-></span><span class="identifier">d_name</span><span class="plain">) == </span><span class="constant">0</span><span class="plain">) {</span>
|
|
<span class="identifier">rc</span><span class="plain">++;</span>
|
|
<span class="identifier">strcpy</span><span class="plain">(</span><span class="identifier">last_match</span><span class="plain">, </span><span class="identifier">dirp</span><span class="plain">-></span><span class="identifier">d_name</span><span class="plain">);</span>
|
|
<span class="plain">}</span>
|
|
<span class="plain">}</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">rc</span><span class="plain">;</span>
|
|
<span class="plain">}</span>
|
|
</pre>
|
|
|
|
<p class="inwebparagraph"></p>
|
|
|
|
<p class="inwebparagraph"><a id="SP5"></a><b>§5. Non-POSIX tail. </b>On platforms without POSIX directory handling, we revert to regular <code class="display"><span class="extract">fopen</span></code>.
|
|
</p>
|
|
|
|
<pre class="display">
|
|
<span class="reserved">FILE</span><span class="plain"> *</span><span class="functiontext">CIFilingSystem::fopen<button class="popup" onclick="togglePopup('usagePopup221')">...<span class="popuptext" id="usagePopup221">Usage of <b>CIFilingSystem::fopen</b>:<br><a href="#SP3">§3</a>, Filenames - <a href="3-fln.html#SP10">§10</a></span></button></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">path</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">mode</span><span class="plain">) {</span>
|
|
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">fopen</span><span class="plain">(</span><span class="identifier">path</span><span class="plain">, </span><span class="identifier">mode</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 undefined.</p>
|
|
|
|
<hr class="tocbar">
|
|
<ul class="toc"><li><a href="3-fln.html">Back to 'Filenames'</a></li><li><a href="3-shl.html">Continue with 'Shell'</a></li></ul><hr class="tocbar">
|
|
<!--End of weave-->
|
|
<script>
|
|
function togglePopup(material_id) {
|
|
var popup = document.getElementById(material_id);
|
|
popup.classList.toggle("show");
|
|
}
|
|
</script>
|
|
|
|
<link href="Popups.css" rel="stylesheet" rev="stylesheet" type="text/css">
|
|
</main>
|
|
</body>
|
|
</html>
|
|
|