Version 1.10 of ais/ai-00248.txt

Unformatted version of ais/ai-00248.txt version 1.10
Other versions for file ais/ai-00248.txt

!standard A.15 (00)          02-01-02 AI95-00248/04
!class amendment 00-11-28
!status work item 00-11-28
!status received 00-11-28
!priority Medium
!difficulty Medium
!subject Directory Operations
!summary
package Ada.Directories is proposed to provide portable access to tree-structured file systems and to provide searching for files.
!problem
Most modern operating systems contain some sort of tree-structured file system. Many applications need to manage these file systems (by creating and removing directories, searching for files, and the like). Most Ada 95 compilers provide some sort of access to the operations needed to manage these systems. But, these packages differ in many ways, making portable Ada 95 programs impossible.
The POSIX libraries provide operations for doing this, but these usually are available only on POSIX systems, leaving out many popular operating systems including MS-DOS, most flavors of Windows, and even Linux.
Ada 95 has already opened the door to standard packages that are not necessarily applicable to all implementations with Ada.Command_Line.
!proposal
(See wording.)
!wording
Static Semantics
with Ada.IO_Exceptions; with Ada.Calendar; package Ada.Directories is
-- Directory and file operations:
function Current_Directory return String; procedure Set_Directory (Directory : in String);
procedure Create_Directory (New_Directory : in String; Form : in String := "");
procedure Delete_Directory (Directory : in String);
procedure Create_Path (New_Directory : in String; Form : in String := "");
procedure Delete_Tree (Directory : in String);
procedure Delete_File (Name : in String);
procedure Rename (Old_Name, New_Name : in String);
procedure Copy_File (Source_Name, Target_Name : in String);
-- File and directory name operations:
function Full_Name (Name : in String) return String;
function Simple_Name (Name : in String) return String;
function Containing_Directory (Directory : in String) return String;
function Extension_Name (Name : in String) return String;
function Base_Name (Name : in String) return String;
function Compose (Containing_Directory, Name, Extension : in String := "") return String;
-- File and directory queries:
type File_Kind is (Directory, Ordinary_File, Special_File);
type File_Size is range 0 .. <implementation-defined>;
function Kind (Name : in String) return File_Kind;
function Size (Name : in String) return File_Size;
function Modification_Time (Name : in String) return Ada.Calendar.Time;
-- Directory searching:
type Directory_Entry_Type is limited private;
type Filter_Type is array (File_Kind) of Boolean;
type Search_Type is limited private;
function Is_Valid (Search : in Search_Type) return Boolean;
procedure Start_Search (Search : in out Search_Type; Directory : in String; Pattern : in String; Filter : in Filter_Type := (others => True));
procedure End_Search (Search : in out Search_Type);
procedure Get_Next_Match (Search : in out Search_Type; Directory_Entry : out Directory_Entry_Type);
-- Operations on Directory Entries: function Is_Valid (Directory_Entry : in Directory_Entry_Type) return Boolean;
function Simple_Name (Directory_Entry : in Directory_Entry_Type) return String;
function Full_Name (Directory_Entry : in Directory_Entry_Type) return String;
function Kind (Directory_Entry : in Directory_Entry_Type) return File_Kind;
function Size (Directory_Entry : in Directory_Entry_Type) return File_Size;
function Modification_Time (Directory_Entry : in Directory_Entry_Type) return Ada.Calendar.Time;
Status_Error : exception renames Ada.IO_Exceptions.Status_Error; Name_Error : exception renames Ada.IO_Exceptions.Name_Error; Use_Error : exception renames Ada.IO_Exceptions.Use_Error; Device_Error : exception renames Ada.IO_Exceptions.Device_Error;
private -- Not specified by the language. end Ada.Directories;
External files may be classified as directories, special files, or ordinary files. A @i<directory> is an external file that is a container for files on the target system. A @i<special file> is an external file that cannot be created or read by a predefined Ada Input-Output package. External files that are not special files or directories are called @i<ordinary files>.
AARM Ramification: A directory is an external file, although it may not have a name on some targets. A directory is not a special file, as it can be created and read by Ada.Directories.
AARM Discussion: Devices and soft links are examples of special files on Windows and Unix.
Even if an implementation provides a package to create and read on soft links, such links are still special files.
A @i<file name> is a string identifying an external file. Similarly, a @i<directory name> is a string identifying a directory. The interpretation of file names and directory names is implementation-defined.
The @i<full name> of an external file is a full specification of the name of the file. If the external environment allows alternative specifications of the name (for example, abbreviations), the full name should not use such alternatives. A full name typically will include the names of all of directories that contain the item. The @i<simple name> of an external file is the name of the item, not including any containing directory names. Unless otherwise specified, a file name or directory name parameter to a predefined Ada input-output subprogram can be a full name, a simple name, or any other form of name supported by the implementation.
AARM Discussion: The full name on Unix is a complete path to the root. For Windows, the full name includes a complete path, as well as a disk name ("C:") or network share name. For both systems, the simple name is the part of the name following the last '/' (or '\' for Windows). For example, in the name "/usr/randy/ada-directories.ads", "ada-directories.ads" is the simple name.
AARM Ramification: It is possible for a file or directory name to be neither a full name nor a simple name. For instance, the Unix name "../parent/myfile" is neither a full name nor a simple name.
The @i<default directory> is the directory that is used if a directory or file name is not a full name (that is, when the name does not fully identify the containing directories).
AARM Discussion: The default directory is the one maintained by the familar "cd" command on Unix and Windows. Note that Windows maintains separate default directories for each disk drive; implementations should use the natural implementation.
A @i<directory entry> is a single item in a directory, identifying a single external file (including directories and special files).
For each function that returns a string, the lower bound of the returned value is 1.
function Current_Directory return String; Returns the full directory name for the current default directory. The name returned shall be suitable for a future call to Set_Current_Directory. The exception Use_Error is propagated if a default directory is not supported by the external environment.
procedure Set_Directory (Directory : in String); Sets the current default directory. The exception Name_Error is propagated if the string given as Directory does not identify an existing directory. The exception Use_Error is propagated if the external environment does not support making Directory (in the absence of Name_Error) a default directory.
procedure Create_Directory (New_Directory : in String; Form : in String := ""); Create a directory with name New_Directory. The Form can be used to give system-dependent characteristics of the directory; the interpretation of the Form parameter is implementation-defined. A null string for Form specifies the use of the default options of the implementation of the new directory. The exception Name_Error is propagated if the string given as New_Directory does not allow the identification of a directory. The exception Use_Error is propagated if the external environment does not support the creation of a directory with the given name (in the absence of Name_Error) and form.
procedure Delete_Directory (Directory : in String); Delete an existing empty directory with name Directory. The exception Name_Error is propagated if the string given as Directory does not identify an existing directory. The exception Use_Error is propagated if the external environment does not support the deletion of the directory (or some portion of its contents) with the given name (in the absence of Name_Error).
procedure Create_Path (New_Directory : in String; Form : in String := ""); Create zero or more directories with name New_Directory. Each non-existent directory named by New_Directory is created. for example, on a typical Unix system, Create_Tree ("/usr/me/my"); would create directory "me" in directory "usr", then create directory "my" in directory "me". The Form can be used to give system-dependent characteristics of the directory; the interpretation of the Form parameter is implementation-defined. A null string for Form specifies the use of the default options of the implementation of the new directory. The exception Name_Error is propagated if the string given as New_Directory does not allow the identification of any directory. The exception Use_Error is propagated if the external environment does not support the creation of any directories with the given name (in the absence of Name_Error) and form.
procedure Delete_Tree (Directory : in String); Delete an existing directory with name Directory. The directory and all of its contents (possibly including other directories) are deleted. The exception Name_Error is propagated if the string given as Directory does not identify an existing directory. The exception Use_Error is propagated if the external environment does not support the deletion of the directory or some portion of its contents with the given name (in the absence of Name_Error). if Use_Error is propagated, it is unspecified if a portion of the contents of the directory are deleted.
procedure Delete_File (Name : in String); Delete an existing ordinary or special file with Name. The exception Name_Error is propagated if the string given as Name does not identify an existing ordinary or special external file. The exception Use_Error is propagated if the external environment does not support the deletion of the file with the given name (in the absence of Name_Error).
procedure Rename (Old_Name, New_Name : in String); Rename an existing external file (including directories) with Old_Name to New_Name. The exception Name_Error is propagated if the string given as Old_Name does not identify an existing external file. The exception Use_Error is propagated if the external environment does not support the renaming of the file with the given name (in the absence of Name_Error). in particular, Use_Error is propagated if a file or directory already exists with New_Name.
procedure Copy_File (Source_Name, Target_Name : in String); Copy the contents of the existing external file with Source_Name to Target_Name. The resulting external file is a duplicate of the source external file. exception Name_Error is propagated if the string given as Source_Name does not identify an existing external ordinary or special file or if the string given as Target_Name does not allow the identification of an external file. The exception Use_Error is propagated if the external environment does not support the creating of the file with the name given by Target_Name or copying of the file with the name given by Source_Name (in the absence of Name_Error).
AARM Ramification: Name_Error is always raised if Source_Name identifies a directory. It is up to the implementation whether special files can be copied, or if Use_Error will be raised.
function Full_Name (Name : in String) return String; Returns the full name corresponding to the file name specified by Name. The exception Name_Error is propagated if the string given as Name does not allow the identication of an external file (including directories and special files).
AARM Discussion: Full name means that no abbrevations are used in the returned name, and that it is a full specification of the name. Thus, for Unix and Windows, the result should be a full path which does not contain any "." or ".." directories. Typically, the default directory is used to fill in any missing information.
function Simple_Name (Name : in String) return String; Returns the simple name portion of the file name specified by Name. The exception Name_Error is propagated if the string given as Name does not allow the identication of an external file (including directories and special files).
function Containing_Directory (Name : in String) return String; Returns the full name of the containing directory of the external file (including directories) identified by Name. (if more than one directory can contain Name, the directory name returned is implementation-defined.) The exception Name_Error is propagated if the string given as Name does not does not allow the identification of an external file. The exception Use_Error is propagated if the external file does not have a containing directory.
AARM Discussion: If Name is not given as a full name, the default directory is used to determine the name in the manner appropriate for the external environment. For example, if the current directory on Windows is "C:\Ada95\RM" and Containing_Directory ("..\AARM\RM-A-8") is called, the result should be "C:\Ada95\AARM".
function Extension_Name (Name : in String) return String; Returns the extension name corresponding to Name. The extension name is a portion of a simple name (not including any separator characters), typically used to identify the file class. if the external environment does not have extension names, then the null string is returned. The exception Name_Error is propagated if the string given as Name does not does not allow the identification of an external file.
AARM Discussion: For Unix and Windows, the extension is the portion of the simple name following the rightmost period. For example, in the simple name "RM-A-8.html", the extension is "html".
function Base_Name (Name : in String) return String; Returns the base name corresponding to Name. The base name is the remainder of a simple name after removing any extension and extension separators. The exception Name_Error is propagated if the string given as Name does not allow the identication of an external file (including directories and special files).
AARM Discussion: For Unix and Windows, the base name is the portion of the simple name preceding the rightmost period. For example, in the simple name "RM-A-8.html", the base name is "RM-A-8".
function Compose (Containing_Directory, Name, Extension : in String := "") return String; Returns the full name of the external file with the specified Containing_Directory, Name, and Extension. if Extension is the null string, then Name is interpreted as a simple name; otherwise Name is interpreted as a base name. if Containing_Directory is the null string, then the default containing directory is used. The exception Name_Error is propagated if the string given as Containing_Directory is not null and does not allow the identication of a directory, or if the string given as Extension is not null and is not a possible extension, or if the string given as Name is not null and is not a possible simple name (if Extension is null) or base name (if Extension is non-null).
type File_Kind is (Directory, Ordinary_File, Special_File); The type File_Kind represents the kind of file represented by by an external file or directory.
type File_Size is range 0 .. <implementation-defined>; The type File_Size represents the size of an external file.
function Kind (Name : in String) return File_Kind; Returns the kind of external file represented by Name. The exception Name_Error is propagated if the string given as Name does not allow the identication of an existing external file.
function Size (Name : in String) return File_Size; Returns the size of the external file represented by Name. The size of an external file is the number of stream elements that contained in the file. if the external file is discontiguous (not all elements exist), the result is implementation-defined. if the external file is not an ordinary file, the result is implementation-defined. The exception Name_Error is propagated if the string given as Name does not allow the identication of an existing external file. The exception Constraint_Error is propagated if the file size is not a value of type File_Size.
AARM Discussion: We allow raising Constraint_Error, so that an implementation for a system with 64-bit file sizes does not need to support full numerics on 64-bit integers just to implement this package. Of course, if 64-bit integers are available on such a system, they should be used when defining type File_Size.
function Modification_Time (Name : in String) return Ada.Calendar.Time; Returns the time that the external file represented by Name was most recently modified. if the external file is not an ordinary file, the result is implementation-defined. The exception Name_Error is propagated if the string given as Name does not allow the identication of an existing external file. The exception Use_Error is propagated if the external environment does not support the reading the modification time of the file with the name given by Name (in the absence of Name_Error).
type Directory_Entry_Type is limited private; The type Directory_Entry_Type represents a single item in a directory. These items can only be created by the Get_Next_Match procedure in this package. Information about the item can be obtained from the functions declared in this package. A default initialized object of this type shall be invalid.
type Filter_Type is array (File_Kind) of Boolean; The type Filter_Type specifies which directory entries are provided from a search operation. if the Directory component is True, directory entries representing directories are provided. if the Ordinary_File component is True, directory entries representing ordinary files are provided. if the Special_File component is True, directory entries representing special files are provided.
type Search_Type is limited private; The type Search_Type contains the state of a directory search. A default-initialized Search_Type object is invalid.
function Is_Valid (Search : in Search_Type) return Boolean; Returns True if Search is a valid search, and False otherwise.
procedure Start_Search (Search : in out Search_Type; Directory : in String; Pattern : in String; Filter : in Filter_Type := (others => True)); Starts a search in the directory entry in the directory named by Directory for entries matching Pattern. Pattern represents a file name matching pattern; its interpretation is implementation-defined. Only items which match Filter will be returned. After a sucessful call on Start_Search, the object Search will be a valid search. The exception Name_Error is propagated if the string given by Directory does not identify an existing directory, or if Pattern does not allow the identification of any possible external file or directory. The exception Use_Error is propagated if the external environment does not support the searching of the directory with the given name (in the absence of Name_Error).
AARM Discussion: Pattern should use the pattern matching characters commonly used on the target. For instance, on Unix and Windows, both '*' and '?' should be supported, with their conventional meaning.
procedure End_Search (Search : in out Search_Type); Ends the search represented by Search. After a successful call on End_Search, the object Search will be invalid. The exception Status_Error is propagated if Search is not valid.
procedure Get_Next_Match (Search : in out Search_Type; Directory_Entry : out Directory_Entry_Type); Returns the next Directory_Entry for the search described by Search that matches the pattern and filter. if no further matches are available, Directory_Entry is invalid after this call. It is implementation-defined as to whether the results returned by this routine are altered if the contents of the directory are altered while the Search object is valid (for example, by another program). The exception Use_Error is propagated if the external environment does not support continued searching of the directory represented by Search.
function Is_Valid (Directory_Entry: in Directory_Entry_Type) return Boolean; Returns True if Directory_Entry is valid, and False otherwise.
function Simple_Name (Directory_Entry : in Directory_Entry_Type) return String; Returns the simple external name of the external file (including directories) represented by Directory_Entry. The format of the name returned is implementation-defined. The exception Status_Error is propagated if Directory_Entry is invalid.
function Full_Name (Directory_Entry : in Directory_Entry_Type) return String; Returns the full external name of the external file (including directories) represented by Directory_Entry. The format of the name returned is implementation-defined. The exception Status_Error is propagated if Directory_Entry is invalid.
function Kind (Directory_Entry : in Directory_Entry_Type) return File_Kind; Returns the kind of external file represented by Directory_Entry. The exception Status_Error is propagated if Directory_Entry is invalid.
function Size (Directory_Entry : in Directory_Entry_Type) return File_Size; Returns the size of the external file represented by Directory_Entry. The size of an external file is the number of stream elements that contained in the file. if the external file is discontiguous (not all elements exist), the result is implementation-defined. if the external file represented by Directory_Entry is not an ordinary file, the result is implementation-defined. The exception Status_Error is propagated if Directory_Entry is invalid. The exception Constraint_Error is propagated if the file size is not a value of type File_Size.
function Modification_Time (Name : in String) return Ada.Calendar.Time; Returns the time that the external file represented by Directory_Entry was most recently modified. if the external file represented by Directory_Entry is not an ordinary file, the result is implementation-defined. The exception Status_Error is propagated if Directory_Entry is invalid. The exception Use_Error is propagated if the external environment does not support the reading the modification time of the file with the name given by Name (in the absence of Name_Error).
Implementation Requirements
For Copy_File, if Source_Name identifies an existing external ordinary file created by a predefined Ada Input-Output package, and Target_Name can be used in the Create operation of that Input-Output package with mode Out_File without raising an exception, then then Copy_File shall not propagate Use_Error.
AARM Discussion: This means that Copy_File will copy any file that the Ada programmer could copy (by writing some possibly complicated Ada code).
Implementation Advice
If other information about a file is available (such as the size or creation date) in a directory entry, the implementation should provide functions in a child package Ada.Directories.Information to retrieve it.
Start_Search should raise Use_Error if Pattern is malformed, but not if it could represent a file in the directory but does not actually do so.
For Rename, if both New_Name and Old_Name are simple names, then Rename should not propagate Use_Error.
AARM Discussion: This cannot be a requirement, since we we have to allow Use_Error to be raised (for instance, because the user may not have permission to rename the file, even if New_Name doesn't exist and is a valid name).
Notes
The file name operations Containing_Directory, Full_Name, Simple_Name, Base_Name, Extension, and Compose operate on file names, not external files. The files identified by these operations do not need to exist. Name_Error is raised only if the file name is malformed and cannot possibly identify a file.
Values of Search_Type and Directory_Entry_Type can be saved and queried later. However, another task or application can modify or delete the file represented by a Directory_Entry_Type value or the directory represented by a Search_Type value; such a value can only give the information valid at the time it is created. Therefore, long-term storage of these values is not recommended.
If the target system does not support directories inside of directories, Is_Directory will always return False, and Containing_Directory will always raise Use_Error.
If the target system does not support creation or deletion of directories, Create_Directory, Create_Path, Delete_Directory, and Delete_Tree will always propagate Use_Error.
The second sentence of A.8.2(22) is deleted. (The Full_Name function provides the needed functionality without any overhead on Open and Create.)
!example
Searching a directory for all files with a particular file type:
with Ada.Text_IO, Ada.Directories; procedure Find_Executables is Search : Ada.Directories.Search_Type; Item : Ada.Directories.Directory_Entry_Type; use type Ada.Directories.Directory_Entry_Type; begin Ada.Directories.Start_Search (Search => Search,
Directory => "C:\Bin", Pattern => "*.EXE", Filter => Ada.Directories.Only_Files); loop Ada.Directories.Get_Next_Match (Search => Search,
Directory_Entry => Item); exit when not Ada.Directories.Is_Valid (Item); -- Already have all matches. Ada.Text_IO.Put_Line ("Found file: " & Ada.Directories.Simple_Name(Item)); -- Do something with the file. end loop; Ada.Directories.End_Search (Search => Search); end Find_Executables;
!discussion
The proposed package is based on the existing Claw package (Claw.Directories) [which was designed for Microsoft Windows only], the Ada POSIX bindings, and the GNAT package GNAT.Directory_Operations.
The Ada POSIX bindings cannot be used directly, because they are rather UNIX-centric. For instance, Create_Directory takes a POSIX_Permissions parameter, which is very difficult to map to another operating system. They also define an entire new set of exceptions, which would complicate the definition of the feature.
The names of the routines are based on those used in POSIX and GNAT. Claw uses shorter names based on the idea that the parameter and/or prefix will make it clear what type of object is being created. For example, Create_Directory is Create, and Current_Directory is Current. This seems too radical.
We considered unifying the Delete_File and Delete_Directory operations as Delete, which would slightly simplify the description of the operation. However, since both Unix and Windows use different system calls to implement Delete_File and Delete_Directory, the implementation would be substantially more complex (requiring determining the file kind before proceeding). That seemed to complex, especially as the programmer typically knows whether they are deleting a file or directory.
POSIX and Claw provide an iterator verion of the directory searching mechanism. An earlier version of the proposal used the iterator version in preference to the current object-based version. The iterator version was dropped because a significant number of reviewers had problems understanding how it works. The object-based version is considerably easier to understand.
POSIX and GNAT provide only the item name as a result from a directory search operation. This package provides an private type, in order that other information can be provided, such as the file size and modification time. Moreover, we encourage providing other information if it is available. (For instance, Windows provides creation and last access time stamps in a directory entry.) Of course, using such information is not portable. The implementation advice above shows the intent.
The package is defined as a child of Ada. This is necessary as the package is designed to work with all kinds of files, so it would be inappropriate for it to be a child of any specific IO package, and making it a child of IO_Exceptions also seems inappropriate. Moreover, we could cause conflicts by defining grandchildren of Ada, but not for children of Ada (since it is illegal to compile children of Ada, and implementors should not define their own, while there are no such restrictions for grandchildren of Ada).
A.8.2(22) has long been tested by the ACATS as a requirement. A proper implementation of this rule is expensive, as every open must save the full name in order to be tolerant of changes in the default directory. (An Ada 95 implementation could be unfriendly and ignore changes in the default directory, but the advent of this package would make that implementation incorrect). It is better to provide those operations to those who need them; so Full_Name is included with this package (with a requirement to support the old A.8.2(22)), and the rule has been deleted from A.8.2(22). Thus, the effect of the Ada 95 Name can be provided by:
Ada.Directories.Full_Name(Name(File))
directly after opening a file without the overhead for users that don't need it.
!ACATS Test
ACATS test(s) need to be created.
!appendix

From: Randy Brukardt
Sent: Wednesday, October 04, 2000 9:35 PM

Most modern operating systems contain some sort of tree-structured file
system. Many applications need to manage these file systems (by creating and
removing directories, searching for files, and the like). Most Ada 95
compilers provide some sort of access to the operations needed to manage
these systems. But, these packages differ in many ways, making portable Ada
95 programs impossible.

The POSIX libraries provide operations for doing this, but these usually are
available only on POSIX systems, leaving out many popular operating systems
including MS-DOS, most flavors of Windows, and even Linux.

Ada 95 has already opened the door to standard packages that are not
necessarily applicable to all implementations with Ada.Command_Line.

Therefore, I am proposing a package Ada.Directories. This package is based
on the existing Claw package (Claw.Directories) [which was designed for
Microsoft Windows only], the Ada POSIX bindings, and the GNAT package
GNAT.Directory_Operations.




Static Semantics

with Ada.IO_Exceptions;
package Ada.Directories is

    function Get_Current_Directory return String;
    procedure Set_Current_Directory (Directory : in String);

    procedure Create_Directory (New_Directory : in String;
                                              Form : in String := "");

    procedure Remove_Directory (Directory : in String);

    type Directory_Entry_Type is private;
    No_Directory_Entry : constant Directory_Entry_Type;

    type Filter_Type is (Everything, Only_Directories, Only_Files);
    generic
        with procedure Action (Directory_Entry: in     Directory_Entry_Type;
                                         Quit           : in out Boolean);
    procedure For_Every_Directory_Entry (Directory : in String);

    generic
        with procedure Action (Directory_Entry: in     Directory_Entry_Type;
                                         Quit           : in out Boolean);
    procedure For_Matching_Directory_Entries (Directory : in String;
                                         Pattern : in String;
                                         Returns : in Filter_Type :=
Claw.Directories.Everything);

    -- Operations on Directory Entries:
    function Is_Valid (Directory_Entry: in Directory_Entry_Type) return
Boolean;

    function Name_of (Directory_Entry : in Directory_Entry_Type) return
String;

    function Is_Directory (Directory_Entry : in Directory_Entry_Type) return
Boolean;
    function Is_Ordinary_File (Directory_Entry : in Directory_Entry_Type)
return Boolean;

    Name_Error : exception renames Ada.IO_Exceptions.Name_Error;
    Use_Error : exception renames Ada.IO_Exceptions.Use_Error;
    Device_Error : exception renames Ada.IO_Exceptions.Device_Error;

private
    -- Not specified by the language.
end Ada.Directories;

A @i<directory> is a container for files on the target system. A @<directory
name string> is a string identifying a  directory. The interpretation of
directory name strings is implementation-defined. A @i<directory entry> is a
single item in a directory, identifying a single external file or directory.

function Get_Current_Directory return String;
    Returns the directory name string for the current default directory. The
name returned shall be suitable for a future call to Set_Current_Directory.
The exception Use_Error is propagated if the external environment does not
support a default directory.

procedure Set_Current_Directory (Directory : in String);
    Sets the current default directory. The exception Name_Error is
propagated if string Directory does not identify an existing directory. The
exception Use_Error is propagated if the external environment does not
support making Directory (in the absence of Name_Error) a default directory.

procedure Create_Directory (New_Directory : in String;
                                          Form : in String := "");
    Create a directory with name New_Directory. The Form can be used to give
system-dependent characteristics of the directory; the interpretation of the
Form parameter is implementation-defined. A null string for Form specifies
the use of the default options of the implementation of the new directory.
The exception Name_Error is propagated if string New_Directory does not
identify a possible directory. The exception Use_Error is propagated if the
external environment does not support the creation of a directory with the
given name (in the absence of Name_Error) and Form.

procedure Remove_Directory (Directory : in String);
   Remove an existing directory with name Directory. The exception
Name_Error is propagated if string Directory does not identify an existing
directory. The exception Use_Error is propagated if the external environment
does not support the deletion of the directory with the given name (in the
absence of Name_Error).

type Directory_Entry_Type is private;
   The type Directory_Entry_Type represents a single item in a directory.
These items can only be created by the generic directory searching
procedures in this package. Information about the item can be obtained from
the functions declared in this package. No_Directory_Entry represents an
invalid directory entry. A default initialized object of this type shall be
set to No_Directory_Entry.

type Filter_Type is (Everything, Only_Directories, Only_Files);
   The type Filter_Type specifies which directory entries are provided from
a search operation. Everything specifies that all matching directory entries
are provided. Only_Directories specifies that only directory entries
representing directories are provided. Only_Files specifies that only
directory entries representing ordinary files (not directories) are
provided.

generic
     with procedure Action (Directory_Entry: in     Directory_Entry_Type;
                                      Quit           : in out Boolean);
procedure For_Every_Directory_Entry (Directory : in String);
   Calls Action once for each directory entry in the directory named by
Directory. When Action is called, Directory_Entry contains a valid directory
entry, and Quit is False. If Action sets Quit to True,
For_Every_Directory_Entry finishes with no further calls to action.  The
exception Name_Error is propagated if string Directory does not identify an
existing directory. The exception Use_Error is propagated if the external
environment does not support the searching of the directory with the given
name (in the absence of Name_Error).

generic
     with procedure Action (Directory_Entry: in     Directory_Entry_Type;
                                      Quit           : in out Boolean);
procedure For_Matching_Directory_Entries (Directory : in String;
                                      Pattern : in String;
                                      Returns : in Filter_Type :=
Claw.Directories.Everything);
   Calls Action once for each directory entry in the directory named by
Directory which matches Returns and Pattern. Pattern represents a file name
matching pattern; its interpretation is implementation-defined. When Action
is called, Directory_Entry contains a valid directory entry, and Quit is
False. If Action sets Quit to True, For_Every_Directory_Entry finishes with
no further calls to action.  The exception Name_Error is propagated if
string Directory does not identify an existing directory, or if Pattern does
not identify any possible file. The exception Use_Error is propagated if the
external environment does not support the searching of the directory with
the given name (in the absence of Name_Error).

function Is_Valid (Directory_Entry: in Directory_Entry_Type) return Boolean;
   Returns True if Directory_Entry is valid, and False otherwise.

function Name (Directory_Entry : in Directory_Entry_Type) return String;
   Returns the external name of the file, directory, or other item
represented by Directory_Entry. The format of the name returned is
implementation-defined. The exception Use_Error is propagated if
Directory_Entry is invalid.

function Is_Directory (Directory_Entry : in Directory_Entry_Type) return
Boolean;
   Returns True if the item represented by Directory_Entry is a directory,
and False otherwise. The exception Use_Error is propagated if
Directory_Entry is invalid.

function Is_Ordinary_File (Directory_Entry : in Directory_Entry_Type) return
Boolean;
   Returns True if the item represented by Directory_Entry is an ordinary
file (not a directory), and False otherwise. The exception Use_Error is
propagated if Directory_Entry is invalid.


Implementation Advice

If other information about a file is available (such as the size or creation
date) in a directory entry, the implementation should provide functions in a
child package Ada.Directories.Information to retrieve it.

The name returned by Name should be a file name without any directory
information.

Notes

Values of Directory_Entry_Type can be copied and queried later. However,
another task or application can modify or delete the file represented by a
Directory_Entry_Type value; such a value can only give the information valid
at the time it is created. Therefore, long-term storage of these values is
not recommended.

If the target system does not support directories inside of directories,
Is_Directory will always return False.

If the target system does not support creation or deletion of directories,
Create_Directory and Remove_Directory will always propagate Use_Error.

Action may not be called at all for For_Every_Directory_Entry and
For_Matching_Directory_Entries if there are no matching directory entries.


Design Notes:

1) The names of the routines are based on those used in POSIX and GNAT. Claw
uses shorter names based on the idea that the parameter and/or prefix will
make it clear what type of object is being created. For example,
Create_Directory is Create, and Get_Current_Directory is Get_Current. This
seems too radical.

2) GNAT and Claw provide an "open" (non-iterator) version of the directory
searching mechanism. I've not included that, because it may not be easy to
provide an operation which can be saved/continued at a (much) later time
(even in the same application.) The iterator eliminates the need to store
the state of searching outside of the package.

3) POSIX and GNAT provide only the item name as a result from a directory
search operation. This package provides an private type, in order that other
information can be provided as it is available. (For instance, Windows
provides various time stamps in a directory entry.) Of course, using such
information is not portable. The implementation advice above shows the
intent.

4) The intent is that Pattern in For_Matching_Directory_Entries matches the
standard on the target system. For instance, on Windows, * and ? are the
wildcard characters. I don't know of a good way to say this.

Comments, brickbats welcome.

****************************************************************

From: Robert Dewar
Sent: Wednesday, October 04, 2000 9:55 PM

I am dubious about trying to standardize functionality of this kind at
this stage. If we do decide that this is a worth while approach then
we should take a comprehensive view of what is needed, rather than carve
out individual pieces haphazardly.

Incidentally, in GNAT, we only make things part of the Ada hierarchy if
we think they are possible candidates for such treatment. The current
set of such files in Ada is:

Ada.Command_Line.Remove
Ada.Direct_IO.C_Streams
Ada.Exceptions.Is_Null_Occurrence
Ada.Sequential_IO.C_Streams
Ada.Streams.Stream_IO.C_Streams
Ada.Strings.Unbounded.Text_IO
Ada.Strings.Wide_Unbounded.Wide_Text_IO
Ada.Task_Identification.Image
Ada.Text_IO.C_Streams
Ada.Wide_Text_IO.C_Streams

The packages we add to System are:

System.Address_Image
System.Assertions
System.Partition_Interface
System.Task_Info
System.Wch_Cnv
System.Wch_Con

It is indeed true that our package GNAT.Directory_Operations is NOT in the
Ada or System hierarchies, which means that we do not consider this suitable
area for standardization. However, if this *is* an area for standardization,
I think that the minimal richness is what is found in the GNAT unit, and I
find the proposed Ada child too bare.

Here is the GNAT spec:

--  Directory operations

--  This package provides routines for manipulating directories. A directory
--  can be treated as a file, using open and close routines, and a scanning
--  routine is provided for iterating through the entries in a directory.

package GNAT.Directory_Operations is

   subtype Dir_Name_Str is String;
   --  A subtype used in this package to represent string values that are
   --  directory names. A directory name is a prefix for files that appear
   --  with in the directory. This means that for Unix systems, the string
   --  includes a final '/', and for DOS-like systems, it includes a final
   --  '\' character. It can also include drive letters if the operating
   --  system provides for this. The final '/' or '\' in a Dir_Name_Str is
   --  optional when passed as a procedure or function in parameter.

   type Dir_Type is limited private;
   --  A value used to reference a directory. Conceptually this value includes
   --  the identity of the directory, and a sequential position within it.

   Null_Dir : constant Dir_Type;
   --  Represent the value for an uninitialized or closed directory.

   Directory_Error : exception;
   --  Exception raised if the directory cannot be opened, read, closed,
   --  created or if it is not possible to change the current execution
   --  environment directory.

   procedure Change_Dir (Dir_Name : Dir_Name_Str);
   --  Changes the working directory of the current execution environment
   --  to the directory named by Dir_Name.
   --
   --  Raises Directory_Error if Dir_Name does not exist.

   procedure Make_Dir (Dir_Name : Dir_Name_Str);
   --  Create a new directory named Dir_Name.
   --
   --  Raises Directory_Error if Dir_Name cannot be created.

   function Get_Current_Dir return Dir_Name_Str;
   --  Returns the current working directory for the execution environment.

   procedure Get_Current_Dir (Dir : out Dir_Name_Str; Last : out Natural);
   --  Returns the current working directory for the execution
   --  environment. The name is returned in Dir_Name; Last is the index in
   --  Dir_Name such that Dir_Name (Last) is the last character written. If
   --  Dir_Name is too small for the directory name, the name will be
   --  truncated before beeing copied to Dir_Name.

   procedure Open (Dir : out Dir_Type; Dir_Name : in Dir_Name_Str);
   --  Opens the directory named by Dir_Name and returns a Dir_Type value
   --  that refers to this directory, and is positioned at the first entry.
   --
   --  Raises Directory_Error if Dir_Name cannot be accessed. In that case
   --  Dir will be set to Null_Dir.

   procedure Close (Dir : in out Dir_Type);
   --  Closes the directory stream refered to by Dir. After calling Close
   --  Is_Open will return False. Dir will be set to Null_Dir.
   --
   --  Raises Directory_Error if Dir has not be opened (Dir = Null_Dir).

   function Is_Open (Dir : Dir_Type) return Boolean;
   --  Returns True if Dir is open, or False otherwise.

   procedure Read
     (Dir  : in out Dir_Type;
      Str  : out String;
      Last : out Natural);
   --  Reads the next entry from the directory and sets Str to the name
   --  of that entry. Last is the index in Str such that Str (Last) is the
   --  last character written. Last is 0 when there is no more file in the
   --  directory. If Str is too small for the file name, the file name will
   --  be truncated before beeing copied to Str. The list of files returned
   --  includes directories in systems providing a hierarchical directory
   --  structure, including . (the current directory) and .. (the parent
   --  directory) in systems providing these entries. The directory is
   --  returned in target-OS form.
   --
   --  Raises Directory_Error if Dir has not be opened (Dir = Null_Dir).

   function Read_Is_Thread_Safe return Boolean;
   --  Indicates if procedure Read is thread safe. On systems where the
   --  target system supports this functionality, Read is thread safe,
   --  and this function returns True (e.g. this will be the case on any
   --  Unix or Unix-like system providing a correct implementation of the
   --  function readdir_r). If the system cannot provide a thread safe
   --  implementation of Read, then this function returns False.

private

   type Dir_Type_Value;
   type Dir_Type is access Dir_Type_Value;

   Null_Dir : constant Dir_Type := null;

end GNAT.Directory_Operations;

****************************************************************

From: Randy Brukardt
Sent: Wednesday, October 04, 2000 10:23 PM

I understand (but disagree) with the rest of your comment. But I am puzzled
by a couple of things:

> Incidentally, in GNAT, we only make things part of the Ada hierarchy if
> we think they are possible candidates for such treatment.

Well, an implementation isn't allowed to add children of Ada, so GNAT
couldn't do that even if it made sense.

> However, if this *is* an area for standardization,
> I think that the minimal richness is what is found in the
> GNAT unit, and I find the proposed Ada child too bare.

The proposal covers virtually all of the functionality of the GNAT package
(with some differences), and adds quite a bit of functionality that the GNAT
package does not have. So I don't know where you get "bare" from.

I looked at the GNAT spec before making the proposal, and used all of the
ideas from it that I could.

> Here is the GNAT spec:

...

>    subtype Dir_Name_Str is String;
   I left out the subtype because it didn't seem to buy anything. The
description of the meaning of the string had to be left out because it
wouldn't be appropriate in the standard.

>    type Dir_Type is limited private;
    This is part of the "open" version of directory searching. Claw has
both, but I think an iterator version would be better suited for
standardization. (I gave the reasons in the notes at the end of the
proposal.)

>    Null_Dir : constant Dir_Type;
    Don't need this if you don't need the above type.

>    Directory_Error : exception;
    I suggested using IO_Exceptions for this, as these are IO operations.
Moreover, we get some of the documentation requirements and definitions for
free in that case, otherwise we have to write them up specifically.

>    procedure Change_Dir (Dir_Name : Dir_Name_Str);
    Called Set_Current_Directory in the proposal. "Dir" is an abbreviation,
and the Ada standard doesn't like abbreviations. If people think "Directory"
is too long, we could change that to "Folder".

>   procedure Make_Dir (Dir_Name : Dir_Name_Str);
    Called Create_Directory in the proposal.

>    function Get_Current_Dir return Dir_Name_Str;
    Called Get_Current_Directory in the proposal.

>    procedure Get_Current_Dir (Dir : out Dir_Name_Str;
>                               Last : out Natural);
    I didn't provide a procedure version of the functions, but if that is
thought to be important, its easy to add.

>    procedure Open (Dir : out Dir_Type; Dir_Name : in Dir_Name_Str);
    Part of the "Open" file searching. Use the iterator
For_Every_Directory_Entry instead.

>    procedure Close (Dir : in out Dir_Type);
    Also part of the "Open" file searching. Not necessary, the iterator does
it automatically.

>    function Is_Open (Dir : Dir_Type) return Boolean;
    Also part of the "Open" file searching. Since there is no object, there
is no need for this.

>    procedure Read
>      (Dir  : in out Dir_Type;
>       Str  : out String;
>       Last : out Natural);
    Also part of the "Open" file searching. The "Action" procedure and the
"Name" function takes the place of this.

>    function Read_Is_Thread_Safe return Boolean;
    This seems too system-specific to be part of the standard.

The proposal, OTOH, offers filtered searching and the capability of
retrieving properties beyond just the name, which are quite useful in my
experience.

****************************************************************

From: Pascal Leroy
Sent: Thursday, October 05, 2000 3:13 AM

> I am dubious about trying to standardize functionality of this kind at
> this stage.

I agree with Robert.

First, I am not sure that there are many applications out there that need to
run on both Unix and Windows (I don't know of any in our installed base; I
know of people migrating from Unix to NT, but that's a different story
altogether).  Moreover, anyone designing such an application will be better
off encapsulating the directory services that they need (and many other OS
services, btw) than relying on an interface that will necessarily be a least
common denominator.

More importantly, we must make the best use of the scare ARG resources.
While a package of directory services would be nice-to-have, it's easy for
users to write their own, so it's not like anyone is stuck waiting for the
ARG to come up with a solution.  On the other hand, there are amendment
proposals on the table that deal with real language holes which cannot be
circumvented in a reasonably simple fashion.

We have add this discussion already when we did the TC: let's focus on the
20% of the issues that will benefit 80% of the users.

****************************************************************

From: Pascal Leroy
Sent: Thursday, October 05, 2000 3:02 AM

> Well, an implementation isn't allowed to add children of Ada, so GNAT
> couldn't do that even if it made sense.

WHAT?!  Hopefully this statement is incorrect, or else the RM needs to be
changed.  As far as I can tell, even the _user_ can add children of Ada
(well, they better know what they are doing, but still they can).

****************************************************************

From: Robert Dewar
Sent: Thursday, October 05, 2000 10:23 AM

<<> Incidentally, in GNAT, we only make things part of the Ada hierarchy if
> we think they are possible candidates for such treatment.

Well, an implementation isn't allowed to add children of Ada, so GNAT
couldn't do that even if it made sense.
>>

But it is allowed to add grandchildren!

****************************************************************

From: Michael Yoder
Sent: Thursday, October 05, 2000 9:27 AM

I assume "Claw.Directories.Everything" should be replaced by "Everything."

****************************************************************

From: David C. Hoos, Sr.
Sent: Thursday, October 05, 2000 5:03 AM

I have six comments about the proposal, viz.:

   1.  I like the proposal, in general.

   2.  There is an obvious error where
       "Claw.Directories.Everything" should simply be
       "Everything"

   3.  The use of verb phrases for function names is not
       recommended by most (if not all) standards.  Therefore
       I would recommend Get_Current_Directory be named
       Current_Directory, instead.

   4.  The function "Name_Of" should be named simply "Name", for
       consistency (e.g.) with Ada.Text_IO.

   5.  The function "Is_Ordinary_File" adds yet another term for
       something that has had a different name for many years.
       I suggest that that function be named "Is_Regular_File."

   6.  The word "Directory" in the names of the generic iterators
       is redundant -- after all, the package is named "Directories,"
       and "Directory" is the formal names for a parameter of these
       iterators.  Long names (i.e. no cryptic abbreviations) are
       useful, up to the point where additional words in the name
       add no new information.

I was puzzled by your statement that "The POSIX libraries ....
leav[e] out ... even Linux."
The florist POSIX/Ada bindings have been available for Linux
for several years.
Even so, the point about those OSs left out is well-taken, and
having this functionality as a child of Ada is a good idea,
in my view.

****************************************************************

From: jj@ddci.dk
Sent: Thursday, October 05, 2000 7:38 AM


It is illegal for the user (in standard mode), see [AARM A.2(4)]
but I don't see how it should be illegal for the implementation.

****************************************************************

From: Randy Brukardt
Sent: Thursday, October 05, 2000 1:27 PM

A couple of responses to comments:

Pascal said:

> First, I am not sure that there are many applications out
> there that need to run on both Unix and Windows (I don't know of any
> in our installed base; I know of people migrating from Unix to NT,
> but that's a different story altogether).

Well, most of the ones I've worked on do in fact run on both. The Janus/Ada
compiler uses these sort of operations for library management. The mini-web
server uses them to provide download listings.

Of course, in both cases, this isn't the *only* non-portable operation.

Pascal continues:

> While a package of directory services would be nice-to-have,
> it's easy for users to write their own, so it's not like anyone is stuck
> waiting for the ARG to come up with a solution.

I think "easy" is the wrong word here, "possible" is more like it. Doing so
requires fairly detailed understanding the API of the OS. However, that
really isn't the point. The point is that (almost?) every Ada compiler
provides this functionality (so it must be important), but they all do it
differently. It is this sort of needless difference that makes real-world
Ada programs less portable than they otherwise would have to be.

> On the other hand, there are amendment proposals on the table that
> deal with real language holes which cannot be circumvented in a
> reasonably simple fashion.

Certainly, and I would be the first to say that those should be dealt with
first. But there aren't that many critical issues (thanks to Tucker's
excellent job that last time around), almost everything proposed falls into
the "nice to have" category. You can't convince me that "Is_Null_Occurrence"
or even 'Object_Size is any more important than this.

Robert Dewar said (responding to me):

><<Well, an implementation isn't allowed to add children of Ada, so GNAT
>couldn't do that even if it made sense.>>

>But it is allowed to add grandchildren!

Yes, of course. But for the sort of significant package (such as this one),
making it a grandchild of some vaguely related package doesn't make a lot of
sense. Certainly, Ada.Text_IO.Directories or Ada.IO_Exceptions.Directories
does not seem like a good idea; so I'm not surprised that the GNAT designers
did not include this functionality in Ada.

David Hoos noted a couple of errors in the proposal. I had changed "Name_of"
to just "Name", but obviously missed the most important place. It's obvious
that I didn't compile this package (as it is intended as a trial ballon, so
I didn't want to spend too long on it).

****************************************************************

From: Tucker Taft
Sent: Thursday, October 05, 2000 1:02 PM

Randy Brukardt wrote:
> ...
> Therefore, I am proposing a package Ada.Directories. This package is based
> on the existing Claw package (Claw.Directories) [which was designed for
> Microsoft Windows only], the Ada POSIX bindings, and the GNAT package
> GNAT.Directory_Operations.
> ...
> Comments, brickbats welcome.

I think this is an important area for standardization.  I am
surprised that others have not repeatedly faced the issue of moving
code between Unix and NT (and Mac for some of us ;-).  Certainly
all the server-side code we develop these days has to run on both
Unix and Win2K/NT.  Even if it runs on only Unix, having to go
to the Posix interface to get these basic capabilities seems
like overkill, especially given that basic File I/O is part of
the Ada library.

****************************************************************

From: Robert Dewar
Sent: Thursday, October 05, 2000 11:05 AM

For GNAT, you cannot add children to Ada unless you use a special
implementors-only switch (this switch of course results in non-standard
behavior). And you cannot add grandchildren either without this
special switch (we take full advantage of the RM permission to restrict
all user additions to standard hierarchies).

By the way, the RM specifically expects there to be modes to control this,
and the relevant RM restriction is:

4   In the standard mode, it is illegal to compile a child of package Ada.

which says nothing about grandchildren, and this omission is quite
deliberate (or at least I have always assumed it is, since it is really
quite important for an implementation to be able to add grandchildren).

<<WHAT?!  Hopefully this statement is incorrect, or else the RM needs to be
changed.  As far as I can tell, even the _user_ can add children of Ada
(well, they better know what they are doing, but still they can).
>>

Well you may want to change it, but you have had five years to make that
comment, and have not done so, so it is a bit late now to make a late
and very big change to the language! What possible benefit would there
be in changing the language at this stage. Sounds like you just did not
read the RM carefully here :-) :-)

Note that the deliberateness of the decision here can be assessed by
the following paras in the AARM:

        4.a   Reason:  The intention is that mentioning, say, Ada.Text_IO in
        a with_clause is guaranteed (at least in the standard mode) to refer
        to the standard version of Ada.Text_IO.  The user can compile a root
        library unit Text_IO that has no relation to the standard version of
        Text_IO.

        4.b   Ramification:  Note that Ada can have non-language-defined
        grandchildren, assuming the implementation allows it.  Also, packages
        System and Interfaces can have children, assuming the implementation
        allows it.

        4.c   Implementation Note:  An implementation will typically support
        a nonstandard mode in which compiling the language defined library
        units is allowed.  Whether or not this mode is made available to
        users is up to the implementer.

        4.d   An implementation could theoretically have private children of
        Ada, since that would be semantically neutral.  However, a programmer
        cannot compile such a library unit.

So I don't think there is an issue here, merely some language design
points which Pascal had overlooked :-)

****************************************************************

From: Robert Dewar
Sent: Thursday, October 05, 2000 11:00 AM

<<First, I am not sure that there are many applications out there that need to
run on both Unix and Windows (I don't know of any in our installed base; I
know of people migrating from Unix to NT, but that's a different story
altogether).  Moreover, anyone designing such an application will be better
off encapsulating the directory services that they need (and many other OS
services, btw) than relying on an interface that will necessarily be a least
common denominator.
>>

Well I have to comment that we have many users who are working on
applications that have to work on both Unix and NT, but then this is
something that GNAT works hard to accomodate, so the difference is not
surprising. Actually note that many libraries, as opposed to applications
have to solve this problem (in contexts other than GNAT, including
I am sure most or all other Ada 95 compilers). For example, CLAW is
a library that must work on NT and Unix, even if a given app does not.

Still I think it will be relatively difficult to proceed in standardizing
this, although reading Randy's latest message makes me more sympathetic
to the effort (after all this is something any C programmer can deal
with in a portable manner, why should it be non-portable in Ada?)

And regarding the last sentence, the whole point in portable libraries
is to depend on the least common denominator if you want to be portable.

Also, migration is NOT such a "different story altogether". By making
this portable, you eliminate one more task involved in such migration.

Of course in practice all vendors have decent solutions to this problem
(at least I would assume that is the case). The question is whether it
is worth trying to abstract a common approach, and I must say I am
somewhere in the middle on this issue at this stage, so let's see what
other people think.

****************************************************************

From: Pascal Leroy
Sent: Thursday, October 05, 2000 3:35 PM

> So I don't think there is an issue here, merely some language design
> points which Pascal had overlooked :-)

Surely I was wrong when I said that users can compile a child of Ada: that's
clearly forbidden by RM95 A.2(4).

However, I don't see that this paragraph forbids implementation-defined
children of Ada.  I can't find a requirement that says
"implementation-defined units have to be compiled in the standard mode".
Surely an implementation-defined child of Ada will not be compiled in the
standard mode, but that's part of the black magic that takes place when the
implementers prepare their predefined libraries.  (To be honest, I may have
a biased view here because we use a library-based compilation model; not
sure how that works with a source-based model.)

****************************************************************

From: Pascal Leroy
Sent: Thursday, October 05, 2000 3:42 PM

> > On the other hand, there are amendment proposals on the table that
> > deal with real language holes which cannot be circumvented in a
> > reasonably simple fashion.
>
> Certainly, and I would be the first to say that those should be dealt with
> first. But there aren't that many critical issues (thanks to Tucker's
> excellent job that last time around), almost everything proposed falls into
> the "nice to have" category. You can't convince me that "Is_Null_Occurrence"
> or even 'Object_Size is any more important than this.

Mutually-dependent types, unchecked-union, access-to-constant parameters,
access type conversions, meaning of Bit_Order, revised rules for
dispatching, T'Class as generic actual: these are much more important issues
IMHO than taking a random package and trying to standardize it.

****************************************************************

From: Michael Yoder
Sent: Thursday, October 05, 2000 2:21 PM

Pascal wrote:

>More importantly, we must make the best use of the scare ARG resources.
>While a package of directory services would be nice-to-have, it's easy for
>users to write their own, so it's not like anyone is stuck waiting for the
>ARG to come up with a solution.  On the other hand, there are amendment
>proposals on the table that deal with real language holes which cannot be
>circumvented in a reasonably simple fashion.
Pascal wrote:

>We have add this discussion already when we did the TC: let's focus on the
>20% of the issues that will benefit 80% of the users.
>
>Pascal

I agree with Pascal's sentiment but I may disagree with where this issue
lands.  I would say lack of simple directory operations has the most common
annoying impediment to my programming for quite some time.  (The systems
for which I write common code are VMS and Unix.)

That is, my current belief is that this *is* worth the use of scarce
resources; it isn't a strongly held opinion.  It seems to me that even if
this were low payoff, it's also low effort, which may make it worthwhile
regardless.

****************************************************************

From: Jean-Pierre Rosen
Sent: Thursday, October 05, 2000 12:29 PM

From: "Randy Brukardt" <Randy@RRSoftware.Com>
>[...]

> Therefore, I am proposing a package Ada.Directories. This package is based
> on the existing Claw package (Claw.Directories) [which was designed for
> Microsoft Windows only], the Ada POSIX bindings, and the GNAT package
> GNAT.Directory_Operations.
>
This is certainly a good idea - I had it also ;-) .

May I suggest that you have a look at package OS_Services which is available
from Adalog's components page (http://pro.wanadoo.fr/adalog/compo2.htm). I take
a different approach to scanning and obtaining information about directory
entries. One of the main ideas of my approach was to set up a structure that can
provide OS specific services without affecting portability for programs that
don't use them, i.e. don't restrict to a least common denominator. Maybe we
cannot come up with a solution that takes the best of both worlds.

****************************************************************

From: Robert Dewar
Sent: Thursday, October 05, 2000 7:18 PM

<<I agree with Pascal's sentiment but I may disagree with where this issue
lands.  I would say lack of simple directory operations has the most common
annoying impediment to my programming for quite some time.  (The systems
for which I write common code are VMS and Unix.)
>>

Well I must say that our impression from users is that they are quite
happy to use the package we provide, and we do not have the impression
that this is a significant problem.

****************************************************************

From: Robert Dewar
Sent: Thursday, October 05, 2000 7:15 PM

<<However, I don't see that this paragraph forbids implementation-defined
children of Ada.  I can't find a requirement that says
"implementation-defined units have to be compiled in the standard mode".>>

That's a real stretch. Look at the paragraphs in the AARM

        4.a   Reason:  The intention is that mentioning, say, Ada.Text_IO in
        a with_clause is guaranteed (at least in the standard mode) to refer
        to the standard version of Ada.Text_IO.  The user can compile a root
        library unit Text_IO that has no relation to the standard version of
        Text_IO.

        4.b   Ramification:  Note that Ada can have non-language-defined
        grandchildren, assuming the implementation allows it.  Also, packages
        System and Interfaces can have children, assuming the implementation
        allows it.

This pretty clearly implies that Ada can NOT have non-language-defined
children, and this is surely the intent.

<<Surely an implementation-defined child of Ada will not be compiled in the
standard mode, but that's part of the black magic that takes place when the
implementers prepare their predefined libraries.  (To be honest, I may have
a biased view here because we use a library-based compilation model; not
sure how that works with a source-based model.)
>>

There is absolutely no difference here that results from the compilation
model. In either case, there needs to be a special mechanism for adding
children to Ada. But I think it would be quite wrong for an implementor
to provide implementation defined children of Ada.

Incidentally, I completely misunderstood Pascal's position here, I thought
he was arguing AGAINST implementation defined grandchildren, and in fact
he appears to be arguing FOR implementation defined children.

****************************************************************

From: Robert A Duff
Sent: Friday, October 06, 2000 9:02 AM

Robert wrote:

> This pretty clearly implies that Ada can NOT have non-language-defined
> children, and this is surely the intent.

Yes, that was the intent, as far as I recall.

****************************************************************

From: Robert A Duff
Sent: Friday, October 06, 2000 9:06 AM

Well, I can't resist making one somewhat-technical comment:

Randy wrote:

>     Called Set_Current_Directory in the proposal. "Dir" is an abbreviation,
> and the Ada standard doesn't like abbreviations. If people think "Directory"
> is too long, we could change that to "Folder".

I don't think we have to avoid the "Dir" abbreviation here.  It's no
worse than the "IO" in "Text_IO".  I could live with "Directory", too.

I really, really hate the term "Folder".

****************************************************************

From: Robert A Duff
Sent: Friday, October 06, 2000 9:01 AM

I have lots of technical comments on Randy's proposal.  However, I think
we should first decide whether (at least tentatively) whether to
standardize this stuff at all.

I'm (mildly) in favor of it.  Can we argue about that first, and perhaps
have a straw poll?  I don't want to waste time arguing about the
technical points if only two people are interested.

Pascal, knowing that priorities are not absolute, but are relative to
each other, wrote:

> Mutually-dependent types, unchecked-union, access-to-constant parameters,
> access type conversions, meaning of Bit_Order, revised rules for
> dispatching, T'Class as generic actual: these are much more important issues
> IMHO than taking a random package and trying to standardize it.

I agree that the following are higher priority than directory ops:
mutually-dependent types, access-to-constant parameters, access type
conversions, T'Class as generic actual.
I don't agree about unchecked-union or meaning of Bit_Order.
I don't remember what "revised rules for dispatching" means.  :-(
On my list, "mutually-dependent types" is highest priority.

Mike Yoder wrote:

> That is, my current belief is that this *is* worth the use of scarce
> resources; it isn't a strongly held opinion.  It seems to me that even if
> this were low payoff, it's also low effort, which may make it worthwhile
> regardless.

Perhaps.  But I'll bet we could spend a LOT of time arguing about
stylistic details.  Also, whether to add one more "nice-to-have"
operation to the package.

****************************************************************

From: Pascal Leroy
Sent: Friday, October 06, 2000 2:57 AM

> It seems to me that even if
> this were low payoff, it's also low effort, which may make it worthwhile
> regardless.

There are really three "efforts" involved here:

1 - The effort needed to standardize this package and its semantics.
2 - The effort needed to write ACAATS tests to ensure that implementers
comply with the specification.
3 - The effort needed to implement the package.

I'm sure that #3 is a very small effort; it really looks like an afternoon
project to me.

Regarding #1: the ARG has demonstrated a surprising ability to argue for
hours about totally trivial details; in fact, it seems that the more trivial
the issue, the more arguments it generates because everybody understands the
issue and has a strong opinion.

Regarding #2, the ARG has not been very good at producing tests for new or
modified capabilities.  The only significant effort in that direction were
the tests that Bob Duff wrote in the ACAATS 2.2 timeframe.  My gut feeling
is that 60% of the changes that went into the corrigendum have no
corresponding test.

My conclusion is that I'd rather devote precious ARG-hours to other topics,
or to writing ACAATS tests for old AIs.

****************************************************************

From: Pascal Leroy
Sent: Friday, October 06, 2000 2:48 AM

> <<However, I don't see that this paragraph forbids implementation-defined
> children of Ada.  I can't find a requirement that says
> "implementation-defined units have to be compiled in the standard mode".>>
>
> That's a real stretch. Look at the paragraphs in the AARM
>
>         4.a   Reason:  The intention is that mentioning, say, Ada.Text_IO
in
>         a with_clause is guaranteed (at least in the standard mode) to
refer
>         to the standard version of Ada.Text_IO.  The user can compile a
root
>         library unit Text_IO that has no relation to the standard version
of
>         Text_IO.

I understand the language design principle of preventing a random user from
unwittingly compiling a package named Ada.Text_IO, thereby resulting in
plague and pestilence.  (Note that you would hope that this same user would
be prevented from compiling a package named Text_IO, too, but she isn't.)

I don't see why it's beneficial to prevent an implementation from providing
a package named Ada.Some_Useful_Services.  Especially when it's OK for them
to provide a root library unit named Some_Useful_Services (which causes
name-space pollution) or a grandchild of Ada named
Ada.Tags.Some_Useful_Services (as is illustrated by the case of directory
services, there are situations where there is no good place to put a
grandchild of Ada).

> This pretty clearly implies that Ada can NOT have non-language-defined
> children, and this is surely the intent.

Even if I followed Robert's logic (and I cannot be too much convinced at
this point) I don't see why it's good.

> Incidentally, I completely misunderstood Pascal's position here, I thought
> he was arguing AGAINST implementation defined grandchildren, and in fact
> he appears to be arguing FOR implementation defined children.

Correct.

****************************************************************

From: Christoph Grein
Sent: Friday, October 06, 2000 1:39 AM

Robert Dewar wrote:
...
> Of course in practice all vendors have decent solutions to this problem
> (at least I would assume that is the case). The question is whether it
> is worth trying to abstract a common approach, and I must say I am
> somewhere in the middle on this issue at this stage, so let's see what
> other people think.

Is this an invitation on a poll? If so, I say it's worth the effort, even if it
provides onlu the least commeon denominator.

What I'm missing and which I think is fundamental is a requirment like

   function Name (Directory_Entry : in Directory_Entry_Type) return String;

   Returns the external name of the file, directory, or other item
   represented by Directory_Entry. The format of the name returned is
   implementation-defined. The exception Use_Error is propagated if
   Directory_Entry is invalid.

=> The returned string shall be usable for Ada.Text_IO file operations
   if Is_Ordinary_File is true for the given Directory_Entry (perhaps
   after an appropriate call to Set_Current_Directory).

As yet IMHO the interaction with Ada.Text_IO is completely unspecified.

****************************************************************

From: Robert Dewar
Sent: Friday, October 06, 2000 10:35 AM

<<I really, really hate the term "Folder".>>

I agree, the term folder would be merely an obfuscation in this
environment (perhaps Randy prefers "transput" to "input-output" since
it is shorter :-)

****************************************************************

From: Robert Dewar
Sent: Friday, October 06, 2000 10:39 AM

<<I agree that the following are higher priority than directory ops:
mutually-dependent types, access-to-constant parameters, access type
conversions, T'Class as generic actual.
I don't agree about unchecked-union or meaning of Bit_Order.
I don't remember what "revised rules for dispatching" means.  :-(
On my list, "mutually-dependent types" is highest priority.>>

Interesting, shows how the view of a language designer can be different
from the view from the applications end.

I would never have included access-to-constant parameters, or access
type conversions, or T'Class as generic actual on my list of important
things. These are simply nice to have, but are not causing anyone any
significant troubles in the field as far as I can see.

Yes, mutually-dependent types are significant, but in our experience,
only in connection with Java environments so far.

The meaning of Bit_Order on the other hand is quite important, and
certainly we implemented this in GNAT because there was significant
demand. Whether or not other compilers standardize this as required
is of course not so signiicant to us.

Similarly, we could not begin to survive without Unchecked_Union.
that's an absolutely vital capability for some of the existing C
bindings.

From a usage point of view, having access to directory operations
is also absolutely vital. An Ada compiler not providing this would
be crippled from the point of view of many users. Whether this means
it should be standardized is another matter.

Robert Dewar
(speaking now as a compiler vendor, and not as a language designer :-)

****************************************************************

From: Pascal Leroy
Sent: Friday, October 06, 2000 10:42 AM

> Pascal, knowing that priorities are not absolute, but are relative to
> each other, wrote:
>
> > Mutually-dependent types, unchecked-union, access-to-constant parameters,
> > access type conversions, meaning of Bit_Order, revised rules for
> > dispatching, T'Class as generic actual: these are much more important issues
> > IMHO than taking a random package and trying to standardize it.
>
> I agree that the following are higher priority than directory ops:
> mutually-dependent types, access-to-constant parameters, access type
> conversions, T'Class as generic actual.
> I don't agree about unchecked-union or meaning of Bit_Order.
> I don't remember what "revised rules for dispatching" means.  :-(

By "revised rules for dispatching" I was alluding to AI-00232.

> On my list, "mutually-dependent types" is highest priority.

On my list, mutually-dependent types and unchecked-unions are the highest
priority items.  I could live without T'Class as generic actual.

Anyway, maybe a first step would be to look at the amendment AIs that are on
the table, and take a straw vote regarding their priority.  The !priority of
the AIs have been assigned by the editor (Bob and Randy) and presumably
reflected their own feeling.  However it would be good to know what topics
are considered high-priority by the ARG as a whole.  This is especially
important for amendment AIs, as they are likely to require considerably more
time than the AIs that merely plug holes in the RM.

****************************************************************

From: Robert Dewar
Sent: Friday, October 06, 2000 10:58 AM

<<I don't see why it's beneficial to prevent an implementation from providing
a package named Ada.Some_Useful_Services.  Especially when it's OK for them
to provide a root library unit named Some_Useful_Services (which causes
name-space pollution) or a grandchild of Ada named
Ada.Tags.Some_Useful_Services (as is illustrated by the case of directory
services, there are situations where there is no good place to put a
grandchild of Ada).
>>

Well Pascal is free to second guess a clear design intention, but as I
say, to change the language here would require a lot of convincing.

Personally, I feel that adding implementation dependent first level
children to Ada would be a horrible idea. Users need to know that
packages in Ada are part of the RM and portable. Yes, I realize
that this argument would apply to grand-children as well, but there
was a concious decision to compromise between two conflicting
requirements here.

I think that implementations should be very judicious in adding new
packages to the Ada hierarchy, even at the grandchild level. I certainly
do not want to encourage profligacy here by allowing children to be
added. For instance I would think it just horrible if we had added
Ada.SPITBOL, rather than GNAT.SPITBOL to our distribution.

Note that the permission in RM (A.3(27)) is interesting:

(ooops, I mean A.3.3(27))

27   An implementation may provide additional packages as children of
Ada.Characters, to declare names for the symbols of the local character set
or other character sets.

Now of course, under all our interpretations, this implementation permission
is junk, since everyone agrees you can add grandchildren anyway, but the
fact that the authors state this explicitly as implementatoin permission
(rather than implementation advice that such packages might be appropriate)
is helpful in understanding the general viewpoint here.

****************************************************************

From: Robert Dewar
Sent: Friday, October 06, 2000 11:07 AM

<<On my list, mutually-dependent types and unchecked-unions are the highest
priority items.  I could live without T'Class as generic actual.>>

OK, I agree with this assessment. Indeed mutually dependent types and
unchecked unions are language extension (yes yes, I know that technically
unchecked union is not an extension :-) tha we provide in GNAT, and which
both our own technology and many of our users programs depend. In the
case of WITH TYPE, we just had to go ahead with our own design (which is
simpler than the full bells-and-whistles proposal from Tucker) in the
absence of an agreed solution, because we absolutely required this for
our Java related work.

As I said earlier, unchecked union also is quite critical (again we find
Tucker's version to have unnecessary bells and whistles, and prefer a
simpler approach :-)

****************************************************************

From: Randy Brukardt
Sent: Friday, October 06, 2000 11:52 AM

> Pascal, knowing that priorities are not absolute, but are relative to
> each other, wrote:
>
> > Mutually-dependent types, unchecked-union, access-to-constant parameters,
> > access type conversions, meaning of Bit_Order, revised rules for
> > dispatching, T'Class as generic actual: these are much more important issues
> > IMHO than taking a random package and trying to standardize it.

To follow up on these messages, I would rank the issues in this order:

AI-0217 (Mutually dependent types)
AI-0230 (implicit conversions between access types)
AI-0222 (Feature control)
AI-0224 (pragma Unsuppress)
AI-0218 (Accidental overriding)
[Unassigned] {Directory operations}
[Unassigned] {Other packages all compilers provide.:-)}
[Unassigned] {'Object_Size}
AI-0216 (Unchecked unions)
AI-0231 (access-to-constant parameters)
AI-0241 (Testing for Null_Occurrence)
AI-0232 (Dispatching operation visibility and ambiguity)
AI-0234 (Unsigned integer types)

I don't think "meaning of Bit_Order" is an amendment. (AI-0133 is classed as
a BI). Similarly with "T'Class as a generic actual type" (AI-0158 is also
classed as a BI). I can believe that the latter is misclassed. I think the
last two on the list are bad ideas that will never go anywhere, thus I gave
them the lowest priority.

There probably are other things that ought to be added to this list, but
those are the ones we have on the table at the moment. We'd probably benefit
from a general discussion of how we'll approach this at the upcoming
meeting.

****************************************************************

From: Randy Brukardt
Sent: Friday, October 06, 2000 4:42 PM

> Robert wrote:
>
> > This pretty clearly implies that Ada can NOT have non-language-defined
> > children, and this is surely the intent.

And Bob replied:

> Yes, that was the intent, as far as I recall.

Randy (who remembers trivia like this, but forgets to check URLs before
sending important announcements...) recalls:

Ada 9X originally had a requirement that a child of Ada could be compiled
only if its name matched a language-defined package. That requirement was
hard to implement (I remember that we did implement it as part of the UI
contracts; we had to look up the name of the unit against a list - yuck),
and still allowed problems, so it was changed to the requirement that now
exists. Certainly, the history of requirement was that no
non-language-defined children of Ada be allowed; the requirement was written
more weakly just so that it was easier to implement.

****************************************************************

From: Jean-Pierre Rosen
Sent: Saturday, October 07, 2000 12:20 AM

> I have lots of technical comments on Randy's proposal.  However, I think
> we should first decide whether (at least tentatively) whether to
> standardize this stuff at all.
>
It always puzzles me to see that the Ada community refuses to see that anything
can exist before it is rubber-stamped by ISO. After all what made the success of
Java ? That Sun very rapidly pushed lots and lots of components - even at the
cost of quality, see the number of deprecated features.

If we (an informal group) can agree on a sufficiently useful package, and can
get compiler vendors to provide the package, that's good enough from a user's
point of view. If the package gets widely used, it can make its way in an annex
for the next revision. No need to waste ARG time on this. After all, that's what
the PAS way at ISO is.

****************************************************************

From: Robert A Duff
Sent: Tuesday, October 10, 2000 11:55 AM

Robert wrote:

> The meaning of Bit_Order on the other hand is quite important, and
> certainly we implemented this in GNAT because there was significant
> demand. Whether or not other compilers standardize this as required
> is of course not so signiicant to us.
>
> Similarly, we could not begin to survive without Unchecked_Union.
> that's an absolutely vital capability for some of the existing C
> bindings.

OK, I guess find the above convincing.

> I think that implementations should be very judicious in adding new
> packages to the Ada hierarchy, even at the grandchild level.

I agree.  The reason for allowing grandchildren is that the
implementation might want to extend an existing (language-defined)
abstraction, so it ought to be a child of that thing,
especially if it needs to know about the private part.

Pascal wrote:

> I don't see why it's beneficial to prevent an implementation from providing
> a package named Ada.Some_Useful_Services.  Especially when it's OK for them
> to provide a root library unit named Some_Useful_Services (which causes
> name-space pollution) ...

Well, the top-level Some_Useful_Services doesn't really pollute the
namespace, because users can just compile their own thing called
Some_Useful_Services.  Anyway, it's logically impossible to forbid
compiler vendors from providing Some_Useful_Services.

> (Note that you would hope that this same user would
> be prevented from compiling a package named Text_IO, too, but she
> isn't.)

As I recall, some people believed (during the 9X process) that this was
a feature -- that you can have your own version of Text_IO.  I wouldn't
do that myself.  But it was intentional that this be allowed.

Robert wrote:

> This by the way is Parkinson's Second Law: The time spent discussing an
> issue is inversely proportional to its importance.

I remember one time when the ARG spent about 20 minutes deciding whether
to take a 15-minute coffee break *now*, versus after doing one more AI.
I believe John Barnes got up and left the room muttering under his
breath.  ;-)

****************************************************************

From: David Emery
Sent: Tuesday, October 10, 2000 1:00 PM

Granted, I'm biased in this respect, but I'd really
suggest that we could reuse the existing POSIX
directories stuff.  The key thing is adding the "spin"
on how this works in Windows.  I think it would be
A Very Bad Thing for Ada to have something that does
not directly align with the existing (and widely
used) POSIX API.

Incidentally, a problem I see with Randy's proposal is
that it's very ambiguous with respect to things in the
file namespace that are not "files" or "directories".
POSIX recognizes lots of stuff in the file namespace,
including character-devices, block-devices, semaphores,
shared memory segments, etc.

****************************************************************

From: bjkae@infomatics.saab.se
Sent: Tuesday, October 10, 2000 1:07 PM

Straw poll vote:

I am in favor of standardizing directory operations.

Standardizing trivial but commonly used operations is very useful.

Ada83 probably suffered a lot as a number of these packages were lacking:
Elementary functions, string operations, command line, etc.

Let us continue the Ada95 way of making things easier also for trivial
programs.

/Björn Källberg

****************************************************************

From: Ted Baker
Sent: Wednesday, October 11, 2000 5:46 AM

As you might expect, I support Dave's suggestion.  --Ted

****************************************************************

From: David Emery
Sent: Wednesday, October 11, 2000 12:22 PM

I think it would be A Good Thing if the directory
operations could be defined in terms of renames on
existing POSIX operations.  This will preserve
signatures and semantics.  For non-POSIX implementations,
the implementor can provide the proper bodies, etc.

****************************************************************

From: Jean-Pierre Rosen
Sent: Thursday, October 12, 2000 2:44 AM

> Granted, I'm biased in this respect, but I'd really
> suggest that we could reuse the existing POSIX
> directories stuff.  The key thing is adding the "spin"
> on how this works in Windows.  I think it would be
> A Very Bad Thing for Ada to have something that does
> not directly align with the existing (and widely
> used) POSIX API.

Then, doing anything would be a waste of time. If you like the POSIX interface,
by all means, use it! Nothing prevents you from having the same interface on
non-POSIX systems.

I think the need that has been expressed here is for something that is NOT
linked to any special OS. There is a challenge here: allowing to be
system-independent while not falling into the least-common-denominator syndrom.
This was my main concern when I wrote OS_Services: define a structure that would
be extensible to allow access to OS pecularities, AND allow a set of common
portable features. If you don't see what I mean, please go to
http://pro.wanadoo.fr/adalog/compo2.htm and download OS_Services. There is a
full HTML documentation that discusses the issues.

****************************************************************

From: David Emery
Sent: Thursday, October 12, 2000 12:49 PM

We do a major dis-service to the community if we
produce a OS-independent package that breaks
lots of existing code for no clear benefit.

It's clear that there is a lot of similarities between
Unix/POSIX, Windows, MacOS, etc in their file systems.
Early in the POSIX work I did a study of how far you
could implement the POSIX API on MS-DOS (I called it
"DOSIX":-)  Most of the POSIX file system packages
could be implemented with minor "semantic spin".

Given that lots of programs are using the POSIX
file packages, it makes sense to me to adopt a
compatible interface for other systems.  This is
particularly true since the major porting efforts
that I've seen that are not Unix->Unix are Unix->Windows.
(And most certainly not Windows->Unix, unfortunately.)
Thus I think the community is best served by preserving
the POSIX API as much as possible.

That's why I suggest that the Directory services be
defined so that they could be implemented using
"renames" of the existing POSIX services.

****************************************************************

From: Tucker Taft
Sent: Thursday, October 12, 2000 5:22 PM

David Emery wrote:
> ...
> Thus I think the community is best served by preserving
> the POSIX API as much as possible.
>
> That's why I suggest that the Directory services be
> defined so that they could be implemented using
> "renames" of the existing POSIX services.

This sounds nice, but we should be sure that we
aren't forcing some kind of artificial simulation
of the Posix path syntax (e.g. blah/blah/blah) onto
the Windows, Mac, VMS, etc. implementations.

How about posting a sample renaming, and perhaps
indicate where there might be a need for some additional
functions, constants, etc.?  Some of us haven't memorized
the Posix interface, and don't have ready access to it.

****************************************************************

From: Jean-Pierre Rosen
Sent: Friday, October 13, 2000 3:39 AM

> We do a major dis-service to the community if we
> produce a OS-independent package that breaks
> lots of existing code for no clear benefit.

I am puzzled by this statement... There IS a Posix binding to Ada, and if a
different package appears, it certainly does not mean that all users of POSIX
*must* give up on Posix and switch to that package!

> [snip]
> Thus I think the community is best served by preserving
> the POSIX API as much as possible.
>
> That's why I suggest that the Directory services be
> defined so that they could be implemented using
> "renames" of the existing POSIX services.

What I'm saying is that if there is not enough added value between the proposed
package and the Posix interface, then it's not worth the effort. I'm viewing
(IMHO) this package as high-level, thick if you wish. I'd rather use a Posix
emulation package on Windows (btw it exists thanks to P. Obry) than an "almost
Posix" package.

****************************************************************

From: Ted Baker
Sent: Tuesday, October 17, 2000 4:05 PM

| I think the need that has been expressed here is for something
| that is NOT linked to any special OS....

The POSIX standard is not linked to any specific OS, any more than
Ada is linked to a specific OS.  POSIX.1 has been implement not just
on a variety of Unix-like systems, but also on Windows NT, VAX VMS,
PrimeOS, and other operating systems.

****************************************************************

From: Robert A Duff
Sent: Tuesday, October 17, 2000 5:26 PM

> The POSIX standard is not linked to any specific OS, any more than
> Ada is linked to a specific OS.  POSIX.1 has been implement not just
> on a variety of Unix-like systems, but also on Windows NT, VAX VMS,
> PrimeOS, and other operating systems.

I would like to hear someone who knows what they're talking about list
the reasons, if any, why POSIX is unsuitable as the "directory
operations" package we're talking about.  Then we can decide "POSIX is
good enough; we don't need anything else" or "we need to design
something based on POSIX that more fully solves the problem" or "POSIX
is irrelevant, so we should design something from scratch (or based on
Randy's package or GNAT's package or whatever)".

****************************************************************

From: Randy Brukardt
Sent: Wednesday, October 18, 2000 12:46 PM

> > The POSIX standard is not linked to any specific OS, any more than
> > Ada is linked to a specific OS.  POSIX.1 has been implement not just
> > on a variety of Unix-like systems, but also on Windows NT, VAX VMS,
> > PrimeOS, and other operating systems.
>
> I would like to hear someone who knows what they're talking about list
> the reasons, if any, why POSIX is unsuitable as the "directory
> operations" package we're talking about.  Then we can decide "POSIX is
> good enough; we don't need anything else" or "we need to design
> something based on POSIX that more fully solves the problem" or "POSIX
> is irrelevant, so we should design something from scratch (or based on
> Randy's package or GNAT's package or whatever)".

I'm not completely sure that I know what I'm talking about here (because I
can only find a late draft of the POSIX standard, not a current version),
but let me try this anyway.

First of all, "Randy's package" is strongly based on the POSIX package. Most
of the subprogram names and functions are the same. My proposal is
essentially that of Bob's second choice. I don't think starting from scratch
makes any sense at all, but that POSIX is not directly a very good choice.

Let me enumerate some of the reasons:

-- All of the package names start with "POSIX". I think this would be very
off-putting to anyone running on a non-POSIX system. This package ought to
be a child of Ada, like Text_IO.

-- The package we standardize has to be meaningful on any target system. (At
least, we have to define what happens when the operations aren't supported.)
The POSIX packages, by definition, do not need to deal with this problem. I
spent quite of bit of effort to define the package such that it would be
meaningful on the largest variety of systems. For instance, it is important
that directory searching work even if the underlying system doesn't support
user-created subdirectories.

-- POSIX exceptions seem to be mapped to the various error codes that a
POSIX system can return. For a standard package, a mapping to IO_Exceptions
is much better. By doing that, we avoid having to explain again all of the
stuff about the meaning of Device_Error and so on.

-- Create_Directory takes a POSIX_Permissions parameter. Ada has
traditionally used Form parameters for this use, which is why my proposal
uses that rather than a "permissions" parameter. I don't think there is any
value to standardizing permissions, especially at this late date.

-- I used the names "Get_Current_Directory" and "Set_Current_Directory"
rather than the POSIX "Change_Working_Directory" and
"Get_Current_Working_Directory" because these are the most meaningful to
someone who usually works on Windows (i.e. me!). I have no objection to
using "Change_Working_Directory" instead of "Set_Current_Directory", but
"Get_Current_Working_Directory" is unnecessarily verbose. If we do change to
the POSIX terminology, we should at least use "Get_Working_Directory" or
just "Working_Directory"; the "current" is redundant.

-- The POSIX operations Change_Working_Directory and
Get_Current_Working_Directory are in the POSIX_Process_Environment package.
While we might want to consider a standard environment package, that is the
wrong place for these routines. That reflects the implementation of the
current (or working) directory, not the usage of them. In particular, some
systems do not sort this information in the environment at all.

-- The POSIX directory searching generic function is not designed for
extensibility. It doesn't have to be: the target is known. A standard
package should, however, be designed so that an implementation can provide
child packages to provide whatever other information is available in the
directory entry.

-- Finally, POSIX does not include any wildcard searching operations, thus
forcing each programmer to implement their own. That is in keeping with the
POSIX tradition, but it is inappropriate for directory searching on most
systems where at least some wildcard processing is part of the operation.
Even without it, the POSIX searching generic can be wildly inefficient: it
makes one call to the Action routine for every item found. If you are
looking only for directories, the vast majority of calls will be false
matches. If the underlying system provides any filters at all, returning
thousands of false matches is silly.

-- POSIX's case sensitivity doesn't bear on this proposal, thank goodness,
but it is a primary reason why using POSIX on Windows is a bad idea. Trying
to impose case sensitivity on a case insensitive file system leads to many
problems, the result being that while POSIX can be used on Windows NT, files
created with it are often incompatible with standard Windows applications.
(The Windows documentation tells you to avoid the POSIX switches unless
you're doing POSIX.)


Now, we could design something radically different than POSIX, but I don't
think that would be justified. But a direct use of POSIX, which clearly had
different goals, especially for portability, than the Ada standard, does not
meet the requirements. (If it did, we should simply be using POSIX for this
purpose.)

****************************************************************

From: Tucker Taft
Sent: Friday, December 01, 2000 4:55 PM

Randy,
    You should probably look at JP Rosen's OS_Services package
as part of working on the "file/directory services" amendment AI.

Reference: http://pro.wanadoo.fr/adalog/compo2.htm

****************************************************************

From the minutes of the Leuven meeting (May 18-20, 2001):

It was noted that the package seems to be too high in the hierarchy of
predefined packages. Randy notes that this package works with all sorts of
files, so it would be inappropriate for it to be a child of any specific IO
package, and making it a child of IO_Exceptions also seems inappropriate. If
Ada 95 had defined a package IO that was the parent of all of the IO packages,
then this package could go there, but of course Ada 95 does no such thing.
Moreover, we could cause conflicts by defining grandchildren of Ada, but not
for children of Ada (since it is illegal to compile children of Ada, and
implementors should not define their own, while there are no such restrictions
for grandchildren of Ada).

Change the name of Get_Current_Directory to Current_Directory.

Steve M. suggests that Remove_Directory ought to say that non-empty directories
are not deleted. After some discussion, it is suggested to add Create_Tree
(which makes all directories needed in the name) and Remove_Tree (delete
everything in the named tree, including directories) to the package. Steve's
suggestion is adopted.

It is also suggested to add Delete (by name [string]) to the package. Rename
(Old_Name, New_Name) should also be added. This should be described as changing
the name of the file from Old_Name to New_Name. There should be an
implementation requirement for this to work at the same level in the same
directory (others may raise Use_Error).

The Name routine for a directory entry should be split into a Simple_Name and
Full_Name routine.

Pascal suggests that there should be some way to get the parent directory.

First Erhard, and then Steve M. express confusion about how the directory
searching iterator works. Randy notes that if Ada experts can't figure out the
POSIX iterator mechanism, what chance do users have? It is suggested to add a
limited (type) handle searching mechanism, rather than the current iterator
scheme. The suggestion is made that the directory searching stuff be put into a
separate child unit to avoid clutter.

Pascal comments that he doesn't like all these operations taking file names,
and that he would prefer a full-fledged Directory_Entry abstraction, much like
Text_IO has a File_Type abstraction. There would be an operation to resolve a
name to obtain a Directory_Entry, and various operations on Directory_Entries.
The group appears unconvinced.

A request for file name composition/decomposition functions was made by Tucker.
Randy notes that these are very tough to do right. The group would like to see
these.

Steve M. would like to see a way to create links. Others note that the links on
Windows or Mac aren't the same as the links on Unix, so a common definition
would be hard.

On Sunday, Randy brings up a recent conformity assessment problem, which is
somewhat related to this AI. A.8.2(22) says "If an external environment allows
alternative specifications of the name (for example, abbreviations), the string
returned by the function should correspond to a full specification of the
name." The ACATS has always tested this as if it were a requirement. However,
some implementations have not been following this requirement (and this fact
was overlooked by the testers). Should this "should" be a "shall" (a
requirement) or shall it remain a "should" (an Implementation Advice)?

There is definitely a serious overhead (it is necessary to call getcwd() on
every Open and Create), and there are implementations which have strayed. The
best solution is to give users an appropriate directories package, and
eliminate this requirement altogether.

Randy says that the immediate problem is three ACATS tests (from ACVC 1.11)
which require this behavior. With the above solution, the best course of action
is to withdraw these tests (they have no other value). The general agreement is
that a good directories package makes this requirement unnecessary. We should
plan to remove this requirement when a directories package is standardized. No
one supported making this a "shall". Randy will integrate this (and associated
operations, such as a Simple_Name => Full_Name routine) into the directories
package.

****************************************************************

From the minutes of the Bloomington meeting (October 5-7, 2001):

Once again the motivation for this AI is questioned. Users want it in the
standard library and with the Ada POSIX interface in jeopardy, it seems to be
necessary.

While the discussion of this AI was scattered among the operations and types of
the package specification, the minutes have organized the discussion and
decisions by how the operations and types were listed:

Create_Path (formerly Create_Tree):

The name Create_Path better describes the intent of this operation than
Create_Tree. A recommendation to add a Boolean parameter for recursion instead
of having a separate routine was defeated by a 3-2-5 straw vote. Create the
directory with name New_Directory with any necessary enclosing directories. Use
the same wording that is found in A.8.2 for files for the raising of
exceptions. The last sentence needs to be changed to refer to "any directories"
instead of a single directory. The description also should say "zero or more",
as this routine does not have to create something.

Current_Directory:

Is the default directory defined? Not really. Default directory is useful for
the use of simple names for directories and files. What it should be is what
would be expected from the underlying environment. But Windows has a default
directory for each device, which is very different from Unix. Then it should
return a full name. Also use the same wording that is found in A.8.2 for files
for the raising of exceptions.

Set_Directory:

Accept simple names (using the default directory as the enclosing directory) or
full name. It was during the discussion of this operation that it was
determined the terms simple names, full names and default directory need better
definitions before the description of operations. (It was noted that
portability is best supported through the use of simple names.)

Delete_Tree (formerly Remove_Tree):

Correct the cut-and-paste error in this description. Use_Error exception is now
raised if it is not able to delete the entire tree (or if that tree does not
exist). It is noted that when Use_Error is raised, it is possible that some
files and/or directories are deleted. A recommendation to add a Boolean
parameter for recursion instead of having a separate routine was defeated by a
2-5-3 straw vote.

At this point the question was raised as to why use the name Remove_Tree
instead of Delete_Tree? The reason given is that most operating systems use the
term remove. But remove is inconsistent with the term delete for files in the
current language. It was decided to use the term delete, so names Delete_File,
Delete_Directory and Delete_Tree will replace Delete (file), Remove_Directory
and Remove_Tree.

Containing_Directory (formerly Parent_Directory):

It was decided to change the name to the new name as the term containing
directory is more descriptive of what is being requested. This function will
return a full name of the directory of the containing directory.

Rename:

It was recommended that the Implementation Advice say the Rename function
should work when both names are simple names.

The discussion brought up the lack of copy operation for files or directories.
It was decided to add a Copy_File operation, but no copy directory. Pascal
cautions about the difficulties with special files on Unix (and similar beasts
on other operating systems). Tuck argues that this shouldn't be a problem for
files created by Ada. Copy_File should be defined to copy files that can be
created by Ada packages, and to have an implementation-defined behavior for
other files.

The discussion turned its attention to the search operations and supporting
types, leaving the discussion of full and simple names for later.

Is_Valid:

The need for this operation is questioned. Randy says that it is a useful test
for determining if a search produced something meaningful and Bob supported his
point. Tuck pointed out that we have the constant No_Directory_Entry for
testing of the result of a search, and therefore that operation Is_Valid
appears to be redundant. If Is_Valid is retained it should mean the same thing
as comparing with No_Directory_Entry. The straw vote on this meaning for
Is_Valid was approved, 6-0-4, but the group decided that the redundacy was
unpleasant and approved removing Is_Valid by a 7-1-2 straw vote. Note: later in
the discussion it was restored!

Start_Search and End_Search:

The Start_Search operation is an iterator operation on the search object.
Consequently Search_Type should be a controlled type to properly support the
finalization of search objects.

There was a discussion on whether a call on End_Search should be optional. If
this is the case, then it means that the finalization of the search object (by
leaving the scope of the object, or by starting a new search with the same
object) has the effect of calling End_Search. The End_Search subprogram should
be retained as a way to release operating system facilities early (i.e., before
leaving the enclosing block). The meeting voted to make calls on End_Search
optional by a 5-2-3 straw vote.

Then there was a recommendation that Start_Search act as a restart, thereby
eliminating the need to explicitly call the End_Search operation to restart a
search. The group approved making Start_Search act as a restart by a 6-2-2
straw vote.

Get_Next_Match:

The only significant issue on the Get_Next_Match operation was how it handled
an unstarted search object: either return No_Directory_Entry in the
Directory_Entry parameter or raise a Status_Error exception. The exception
approach is similar to how the existing file operations handle unopened files
and was approved by 6-3-1. At the end of the iterator, Get_Next_Match returns
No_Directory_Entry.

Is_Directory and Is_Ordinary_File:

The motivation for distinguishing ordinary files is due to the existence of
special files, such as symbolic links to existing files. It was suggested that
a more direct way of distinguishing among directories, ordinary files and
special files was by defining an enumeration type with these values, such as:
   type Directory_Entry_Kind is (Directory, Ordinary_File, Special_File);
and then change the filter type to be:
   type Filter_Type is array (Directory_Entry_Kind) of Boolean;
Consequently the two functions Is_Directory and Is_Ordinary_File are replaced
with a new function Directory_Kind that operates on directory entry objects and
returns the new enumeration type. Also the filter parameter in the Start_Search
operation is changed.

Special files appear to be files that Ada programs can't create or read. Bob
believes there are lots of programs that would like to read soft link files in
order to find the target. If that is the case may be the best way to handle
special files is to provide implementation advice but what is that advice? Does
POSIX provide any directions? Not really because it is allowed to deal with all
files types that this package doesn't want to handle. It was decided the
specifics of special files, such as soft links, should be left to AARM where
operating system details can be discussed.

Composition of simple and full file names:

Randy explained that he borrowed wording for full names from the RM for the
Name operation. He further noted that he did consider Jean-Pierre Rosen's
documentation on composition, where he divided the composition of file
names into these elements:
ú Device
ú Path
ú File
ú Extension
ú Version

This decomposition of file names is meant to be the union of all operating
systems. There is a risk that another operating system does not fit this
composition. Consequently, he decided against adding any operations to
decompose full names. It was noted this list was missing a network element (the
host name).

Should all of this be avoided by putting the details into a child package? Tuck
and Erhard argue that composition of full names for files and directories
should be available in this package. Pascal would like to have some access to
the composition elements without doing string manipulations to get them from
the name strings.

The focus is narrowed to Simple_Name function and the composition functions.
Tuck argues for just one composition function for either directories or files
and let an implementation do the right thing. Portability between systems and
implementation is the goal of this interface and that makes the system-specific
elements, beyond file and directory names and extensions, difficult to expose.

After much discussion, it was decided to take a series of straw votes on how to proceed:
ú On whether this package should provide all three kinds of operations, namely
  compose full file and directory names, extract relative names (the containing
  directory name or the simple name) and file extension operations (extract
  simple name or extension and compose file name with simple name and
  extension), it was defeated by 3-3-4. John commented that he didn't like the
  notion of making "extension" a first-class citizen.
ú The group took a step back to see if there would be agreement on just the
  compose and relative name operations and it did by 8-0-2 straw vote.
ú After taking another straw vote to support more operations (6-3-1), the group
  supported the addition of just the extension operations (i.e., Base,
  Extension and Compose_With_Extension) by 5-2-3.

Erhard would like to have a (modification) time stamp and size operations.
Randy says it is difficult to know what size should be returned, especially in
the presence of 64 bit values and to know how to handle time stamps for
operating systems that do not produce time stamps. For those operating system
with no time stamping, a time stamp operation would raise Use_Error.
Consequently the meeting approved time stamp (meaning the time when the file or
directory was last modified) by consensus.

As for the size of files, it was suggested to let the existing Count type in
Stream_IO package (A.12.1) handle this problem. Unfortunately its bounds may
not be appropriate to deal with very large files. It was decided not to change
the type of count in A.12.1 to be an implementation-defined integer type.
Instead a new signed type should be declared in Directory_Operations; the upper
bound is implementation-defined and the Size function returns values of this
type or raises Constraint_Error if the size is an illegal value for the
implementation. The reason why the group eventually decided on a signed type is
because operations on Size values are common, and we don't want modular
semantics for them. It is implementation defined what the Size function
produces for directories or special files.

All query functions, such as Kind, Modification_Time or Size, should be
applicable to both names and Directory_Entry_Type values.

The term "same containing directory" should replace "same directory location"
in the Implementation Advice on Rename paragraph and the AARM ramification
paragraph should be dropped.

Finally the discussion ended with debating whether Directory_Entry_Type should
be a limited type, since there appears to be no need for its assignment. This
would simplify the implementation and it would be treated similarly to how
files are treated. If assignment is needed, then the program should store a
pointer to it. Consequently this means the constant No_Directory_entry is no
longer needed and the Is_Valid function is restored!

Vote on Intent for all these changes: 7-1-1.

****************************************************************

From: Randy Brukardt
Sent: Monday, January 7, 2002 7:55 PM

Package Ada.Directories (AI-248) contains a basic set of file
composition/decomposition functions.

The only area that I had trouble with in writing up the current design was
with the composition function(s). There were a variety of alternatives,
which I narrowed down to two:

   A single Compose function that returns a file or directory name;

   Separate Compose_Directory and Compose_File_Name functions that return
the item specified.

I choose the first design, because it is consistent with the behavior of the
decomposition functions. For instance, Simple_Name can extract a simple name
from either a file name or directory name.

However, there is a possible problem with this choice: if there exists an
operating system for which file names and directory names are different
syntactically, then the single Compose will not work.
That's because this is intended to be a purely syntactical function, and it
does not require the files or directories to work -- thus it couldn't tell
which to create.

Is this a real concern? (I can't think of any systems with that problem, but
I'm not familiar with them all!) If so, I'll change the proposal to use the
second alternative.

****************************************************************

From: Tucker Taft
Sent: Tuesday, January 8, 2002  12:40 AM

On VMS, directories and files have significantly different syntax.
However, if the "simple_name" that is returned/expected by
decompose/compose retains the special directory syntax
when it refers to a directory, this would not be a problem.  That
is, a "simple_name" in "[]" on VMS would be a directory,
whereas a "simple_name" not enclosed in "[]" would be a file.

So I guess the answer is that the simple_name's syntax
must identify it as a file or a directory, if there is a syntactic
difference.  If that rule is unpleasant, and there is a desire
that "simple_name"s be simple unadorned strings, then you
would seem to need two decomposition and two composition
functions.

****************************************************************

From: Nick Roberts
Sent: Saturday, January 19, 2002  1:48 PM

First, my thanks to Randy for his sharpness in spotting that the original
version of this comment (which has been deleted) was based on an outdated
version of the AI. Well done Randy. I have since corrected this, and
self-administered 20 lashes of the birch in penitance.

My comments in reply to Randy's question (quoted below, hope this doesn't
offend) and pertaining to AI-00248-04 are as follows.

(1) It would seem particularly apt to accompany the introduction of this
package with another, perhaps Ada.Environment, which would provide for the
interrogation of the 'environment strings' that many operating systems use
to communicate information to programs. E.g.:

   package Ada.Environment is

      function Get (Name : in [Wide_]String) return [Wide_]String;

      function Environment_Name    return [Wide_]String;
      function Environment_Version return [Wide_]String;

   end Ada.Environment;

For the Get function, if an environment variable with the requested Name
exists, its value (also a string) is returned, otherwise a null string is
returned.

The Environment_Name function is intended to return a broad identification
of the program's execution environment, e.g. the basic name of an operating
system or RTS. The Environment_Version function is intended to give a more
precise identification of the same. Possible examples of the results of
Environment_Name and Environment_Version might be: "Linux" and "2.4 (Red
Hat 6.2)"; "Windows" and "NT 4.0"; "BSD" and "4.4"; "OS/2" and "4.0".

Admittedly there are a lot of extra possibilities for this package, which
I'll defer to another comment.

(2) I think Wide_String should be used throughout Ada.Command_Line,
Ada.Environment, and Ada.Directories (instead of String). Doing so would
head off a lot of internationalisation [should we use 'i18n' for this word
in future?] problems for the future. I believe making this change for (the
existing package) Ada.Command_Line would cause fewer problems than it would
avoid, in the long term.

(3) It was presumably a little mistake to use the name
Set_Current_Directory (instead of Set_Directory) in the description of the
Current_Directory function. In any case, I would actually prefer the name
Set_Current_Directory for the Set_Directory procedure.

(4) With regard to Create_Path, I would prefer the standard mandated the
behaviour that if any Create (or Create_Directory) - in Ada.Directories or
any of the *_IO packages - names a directory within its path which does not
exist, that directory should be automatically created. There would then be
no need for Create_Path.

This would presumably cause extra work for the implementor of the standard
Ada *_IO packages, but I think it would be worthwhile, especially since it
is something that many application programs would have to do anyway. It
seems to me that, in a situation where a directory somewhere along the path
of a file (or directory) name does not exist, simply creating the necessary
directory would allow the program to continue correctly with its intended
operation, and be very unlikely to do any significant harm. On the other
hand, raising an exception will stymie the program, at least to some
extent. Catching this exception, finding out which directory does not
exist, creating the directory, and then trying again is a lot of bother to
foist onto the application programmer (and done much more easily and
efficiently by an implementation which can use implementation-specific
information and functionality).

(5) Perhaps it would be worth adding the rule that it is an error to
attempt to delete the current default directory; any attempt to do so
should fail and cause Use_Error to be propagated.

(6) I think the Form parameter should be added to the Rename and Copy_File
procedures:

    procedure Rename (Old_Name, New_Name: in String;
                      Form:               in String := "");

    procedure Copy_File (Source_Name, Target_Name: in String;
                         Form:                     in String := "");

to allow implementation-specific information to be added (e.g.
permissions).

The advantage of this approach is that values for the Form parameter could
be read from, say, a configuration file, thus making it possible to make a
portable Ada program have useful implementation-specific behaviour.

Because operations such as file renaming and copying are high-level
operations anyway (likely to require the execution of many tens or hundreds
of thousands of machine instructions), the overhead of interpreting Form
strings is likely to be perfectly acceptable.

(7) If passed a null string, the Containing_Directory function should
return the parent of the current default directory (or the root directory
if the current default directory is the root, or if the OS does not support
hierarchical directories). A null string would then be a useful default
value:

   function Containing_Directory (Name: in String := "") return String;

(8) Maybe the functions Randy was referring to should be as follows.

Remove the Compose function. Add:

   function [Compose_]Directory_Name (
      Simple_Name:          in String;
      Containing_Directory: in String := "" ) return String;

which returns the full name of a directory which represents the path which
starts at Containing_Directory (assumed to already be a valid path), and
adds the directory named Simple_Name. Also add:

   function [Compose_]File_Name (
      Simple_Name:          in String;
      Containing_Directory: in String := "" ) return String;

which returns the full name of a file which represents the path comprising
Containing_Directory and Simple_Name. Finally, add:

   function [Compose_]Simple_Name (
      Base_Name: in String;
      Extension: in String := "" ) return String;

which returns the simple name comprising the given Base_Name and Extension.
E.g. [Compose_]Simple_Name("myfile","txt") = "myfile.txt".

I think the 'Compose_' prefixes are a bit long. Perhaps replacing them with
'To_' would be better.

(9) Please change the name of the type Directory_Entry_Type to just
Directory_Entry, and parameters named Directory_Entry to just Item.
Admittedly this is merely cosmetic, but I do feel these names are wordier
than they need to be.

(10) File_Kind might be defined as follows:

   type File_Kind is (
      Directory,      -- a subdirectory
      Ordinary_File,  -- any file (text or binary)
      Special_File,   -- any non-file nevertheless openable
      Reserved );     -- anything (non-dir) not openable

By 'openable' I mean able to be opened (in general) by the Open procedure
of (at least) one of the *_IO packages (whichever is/are appropriate to the
file or device).

The idea behind the new category (Special_File) is to make provision for
those entities which are openable, but which may not be renamable,
copyable, or deletable (e.g. because they are not normal files). I think
the name Special_File is more appropriate here, and a name such as Reserved
is better for those entities which are 'something else'.

(11) We could have:

   Everything: constant Filter_Type := (others => True);

   Openables: constant Filter_Type :=
                (Ordinary_File | Special_File => True, others => False);

(12) I would like to see the addition of some useful basic pattern helpers,
e.g.:

    Match_All_Names: constant String;

    function Match_Filetype (Filetype: in String) return String;

which would help enable code to be more portable. Match_All_Names might
have the value "*" or "*.*", for example.

(13) The Start_Search procedure could be declared:

   procedure Start_Search (Search:    in out Search_Type;
                           Filter:    in     Filter_Type := Everything;
                           Pattern:   in     String := Match_All_Names;
                           Directory: in     String := "");

The default value of "" for the Directory parameter would specify the
current default directory.

(14) I think the standard should explicitly permit a directory to be locked
by a call to Start_Search; if so it must be unlocked by a call to
End_Search. Obviously most implmentations won't do this, but some may wish
to.

(15) Add:

   function Temporary_Directory return String;

which returns the full name of a temporary directory, which should be
readable, writable, and, preferably, exclusive to the calling program
(process) and initially empty. Returns "" if not available; propagates
Use_Error if not applicable.

(16) Add:

   function Root_Directory (Directory: in String := "") return String;

which returns the full name of a/the root directory (of the physical
storage device on which the directory or directory entry Directory
resides). The default "" for the Directory parameter indicates the current
default directory. Propoagtes Use_Error if N/A. Examples of the result:
"C:\", "/".

(17) Introduce to Ada.Sequential_IO, Ada.Direct_IO, Ada.Text_IO,
Ada.Wide_Text_IO, and Ada.Streams.Stream_IO:

   procedure Rename (File:     in out File_Type;
                     New_Name: in     String;
                     Mode:     in     File_Mode := In_File);

which has the effect of resetting the File object (to the given Mode), and
at the same time renaming it. This procedure would be very useful in
facilitating a typical read-an-original-file,
rewrite-it-to-a-temporary-file, rename-the-original-file, rename-the-
temporary-file cycle. In an environment where there are multiple processes
executing in parallel, and files are locked while open, this procedure
could provide exactly the right locking semantics for the described cycle
(providing the application program also behaves appropriately).

It should also be mandated by the standard that this procedure is
'destructive': if an ordinary file corresponding to New_Name exists, it is
automatically deleted and replaced.

****************************************************************

From: Steve Deller
Sent: Monday, January 21, 2002  1:48 PM

> For the Get function, if an environment variable with the
> requested Name exists, its value (also a string) is returned,
> otherwise a null string is returned.

POSIX environments distinguish "null" from "does not exist".  This
function needs a similar distinction, or perhaps have two functions,
"get" and
    function Exists (Name : in [Wide_]String) return Boolean

> The Environment_Name function is intended to return a broad
> identification of the program's execution environment, e.g.
> the basic name of an operating system or RTS. The
> Environment_Version function is intended to give a more
> precise identification of the same. Possible examples of the
> results of Environment_Name and Environment_Version might be:
> "Linux" and "2.4 (Red Hat 6.2)"; "Windows" and "NT 4.0";
> "BSD" and "4.4"; "OS/2" and "4.0".

How does this differ from the "intent" of System.Name and
System.System_Name?


The rest of the comment seems bent on redefining "POSIX Ada" and adding
it to the LRM.  Is that true?  Where is the proposed specification of
"Ada.Directories"?

****************************************************************


Questions? Ask the ACAA Technical Agent