Rationale for Ada 2012
7.3 Directories
The package Ada.Directories
was introduced in Ada 2005. However, experience with its use has revealed
a number of shortcomings which are rectified in Ada 2012.
Three specific problems are mentioned in
AI-49.
First, it is not possible
to concatenate a root directory such as "/tmp"
with a relative pathname such as "public/file.txt"
using the procedure Compose thus
The_Path: String := Compose("/tmp", "public/file.txt");
This is because the
second parameter of Compose has to be a simple
name such as just "file" if there
is no extension parameter. If we supply the extension parameter thus
The_Path: String := Compose("/tmp", "public/file", "txt");
then the second parameter has to be just a base name
such as "public".
Another problem is
that there is no sensible way to check for a root directory. Thus suppose
the string
S is a directory name and we want
to see whether it is just a root such as
"/"
in Unix then
the only thing that we can do is write
Containing_Directory(S)
which will raise Use_Error
which is somewhat ugly.
We could write if S ="/"
then but this would not be portable from Unix to other systems.
Indeed, the whole purpose of providing file name operations in Ada.Directories
is so that file names can be manipulated in an abstract manner without
fiddling with text strings.
The third problem concerns case sensitivity. At the
moment it is not possible to write portable programs because operating
systems differ in their approach to this issue.
This last problem is solved by adding an enumeration
type Name_Case_Kind and a function Name_Case_Equivalence
to the file and directory name operations of the package Ada.Directories.
So in outline we now have
with Ada.IO_Exceptions;
with Ada.Calendar;
package Ada.Directories
is
...
-- File and directory name operations:
function Full_Name(Name: String) return String;
function Simple_Name(Name: String) return String;
function Containing_Directory(Name: String) return String;
function Extension(Name: String) return String;
function Base_Name(Name: String) return String;
function Compose(
Containing_Directory: String := "";
Name: String;
Extension: String := "")
return String;}
type Name_Case_Kind := (Unknown, Case_Sensitive,
Case_Insensitive, Case_Preserving);
function Name_Case_Equivalence(Name: String) return Name_Case_Kind;
-- File and directory queries:
-- and so on
end Ada.Directories;
The function Name_Case_Equivalence
returns the file name equivalence rule for the directory containing Name.
It raises Name_Error if Name
is not a Full_Name.
It returns Case_Sensitive
if file names that differ only in the case of letters are considered
to be different. If file names that differ only in the case of letters
are considered to be the same, then it returns Case_Preserving
if the name has the case of the file name used when a file is created
and Case_Insensitive otherwise. It returns
Unknown if the name equivalence rule is not
known.
We thus see that Unix and Linux are Case_Sensitive,
Windows is Case_Preserving, and historic systems
such as CP/M and early MS/DOS were Case_Insensitive.
The other problems are solved by the introduction
of an optional child package for dealing with systems with hierarchical
file names. Its specification is
package Ada.Directories.Hierarchical_File_Names
is
function Is_Simple_Name(Name: String) return Boolean;
function Is_Root_Directory_Name(Name: String) return Boolean;
function Is_Parent_Directory_Name(Name: String) return Boolean;
function Is_Current_Directory_Name(Name: String) return Boolean;
function Is_Full_Name(Name: String) return Boolean;
function Is_Relative_Name(Name: String) return Boolean;
function Simple_Name(Name: String) renames Ada.Directories.Simple_Name;
function Containing_Directory(Name: String)
renames Ada.Directories.Containing_Directory;
function Initial_Directory(Name: String) return String;
function Relative_Name(Name: String) return String;
function Compose(
Directory: String := "";
Relative_Name: String;
Extension: String := "") return String;
end Ada.Directories.Hierarchical_File_Names;
Note that the six functions, Full_Name,
Simple_Name, Containing_Directory,
Extension, Base_Name
and Compose in the existing package Ada.Directories
just manipulate strings representing file names and do not in any way
interact with the actual external file system. The same applies to many
of the new functions such as Is_Simple_Name.
In particular, Is_Root_Directory_Name
returns true if the string is syntactically a root and so cannot be decomposed
further. It therefore solves the second problem mentioned earlier. Thus
Is_Root_Directory_Name("/")
returns true for Unix. In the case of Windows "C:\"
and "\\Computer\Share" are roots.
The function Is_Parent_Directory_Name
returns true if and only if the Name is ".."
for both Unix and Windows.
The function Is_Current_Directory_Name
returns true if and only if Name is "."
for both Unix and Windows.
The function Is_Full_Name
returns true if the leftmost part of Name
is a root whereas Is_Relative_Name returns
true if Name allows identification of an external
file but is not a full name. Note that relative names include simple
names as a special case.
The functions Simple_Name
and Containing_Directory are just renamings
of those in the parent package and are provided for convenience.
Finally, the functions Initial_Directory,
Relative_Name and Compose
provide the ability to manipulate relative file names and so solve the
problem with Compose mentioned at the beginning
of this section.
Thus Initial_Directory
returns the leftmost directory part of Name
and Relative_Name returns the entire full
name apart from the initial directory portion.
If we apply Relative_Name
to a string that is just a single part of a name then Name_Error
is raised. In particular this happens if Relative_Name
is applied to a name which is a Simple Name, a Root Directory Name, a
Parent Directory Name or a Current Directory Name.
The function Compose
is much like Compose in the parent package
except that it takes a relative name rather than a simple name. It therefore
allows us to write
The_Path: String := Compose("/tmp", "public/file.txt");
as required.
The result of calling Compose
is a full name if Is_Full_Name(Directory)
is true and otherwise is a relative name.
© 2011, 2012, 2013 John Barnes Informatics.
Sponsored in part by: