Rationale for Ada 2012

John Barnes
Contents   Index   References   Search   Previous   Next 

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.

Contents   Index   References   Search   Previous   Next 
© 2011, 2012, 2013 John Barnes Informatics.
Sponsored in part by:
The Ada Resource Association:

    ARA
  AdaCore:


    AdaCore
and   Ada-Europe:

Ada-Europe