Language Change Specification for Directory API

LCS Number: LCS-2016-006c
Version: 1 {18-Jan-2017}
2 {11-Feb-2017}
3 {17-Feb-2017}
4 {21-Feb-2017}
5 {22-Feb-2017}
6 {xx-Feb-2017}
7 {24-Feb-2017}
8 {15-Mar-2017}
Date: 15-Mar-2017
Status: Voting
Author: Patrick Lehmann
Email: Main.PatrickLehmann
Source Doc: File IO / TextIO updates
Summary: TextIO additions.
See LCS-2016-006a for file I/O additions.

Voting Results: Cast your votes here

Yes:

  1. Yann Guidon - 2017-01-19 - ver 1
  2. Rob Gaddi - 2017-03-16 - ver 8
  3. Lieven Lemiengre - 2017-01-27 - ver 1
  4. Hendrik Eeckhaut - 2017-01-27 ver 1
  5. Kevin Jennings - 2017-2-9 Ver 2
  6. Steve Grout - 2017-03-15 - ver 7
  7. Patrick Lehmann - 2017-03-15 - ver 8
  8. Jim Lewis - 2017-03-15 ver 8

No:

  1. Thomas Preusser - 2017-02-06 - ver 5 - mutable working dir is dangerous, OPEN_DIR joins independent operations needlessly, see comment of 2017-02-22

Abstain:

  1. Brent Hayhoe - 2017-02-16 Version 2 - Abstain due to lack of personal time for review.

Style Notes

Changes are shown in red font.
Deletions are crossed out.
Editing or reviewing notes in green font.

Reviewing Notes

Version 1:
This LCS adds the ability to read directory contents (list all names), query properties (file vs. directory), to create directories and to remove files or directories. The directory's content is returned as a record with an embedded dynamic array of string pointers. Each string contains an item's name. This API does not provide a high-level API: for example to assemble paths or to extract a parent directory from a path. This can be provided by an (open source) package or library.

Version 2:

  • Change DIRECTORY.Childs to DIRECTORY.Items.

Version 4:

  • provide function overloads for the procedure interface to return status values
  • split DIR_DELETE_STATUS into two status enumerations: for directories and files
  • made DIR_SEPARATOR a deferred constant
  • Change wording for recursive deletion of directories
  • specified the Name element in DIRECTORY as a "fully resolved absolute path"

Version 5:

  • reworked STATUS values again
    • In DIR_CREATE_STATUS, changed STATUS_NO_DIRECTORY to STATUS_ITEM_EXISTS.
    • In DIR_DELETE_STATUS, added STATUS_NOT_EMPTY.
  • Reordered out parameter Dir to match the LRM style.
  • Improved text for the impure functions offering another but similar interface to there corresponding procedures.
  • Marked impure function DIR_OPEN as dependent on LCS 002.
  • Listed predefined implicitly declared operators.

Version 6:

  • Rewrote optional parameters in procedures to overloaded procedures to fulfill the coding guide lines.

Version 7:

  • Specified the returned value if an operation fails.

Version 8:

  • Added new overloads for FILE_OPEN as requested.

Details of Language Change

(006c.1) 5.5.2 File operations

The language implicitly defines the operations for objects of a file type. Given the following file type declaration:

type FT is file of TM;

where type mark TM denotes a scalar type, a record type, or a fully constrained array subtype, the following operations are
implicitly declared immediately following the file type declaration:

procedure FILE_OPEN (file F: FT; External_Name: in STRING; Open_Kind: in FILE_OPEN_KIND := READ_MODE);
procedure FILE_OPEN (Status: out FILE_OPEN_STATUS; file F: FT; External_Name: in STRING; Open_Kind: in FILE_OPEN_KIND := READ_MODE);
procedure FILE_OPEN (file F: FT; External_Name: in STRING; Status: out FILE_OPEN_STATUS);
procedure FILE_OPEN (file F: FT; External_Name: in STRING; Open_Kind: in FILE_OPEN_KIND; Status: out FILE_OPEN_STATUS);
impure function  FILE_OPEN (file F: FT; External_Name: in STRING; Open_Kind: in FILE_OPEN_KIND := READ_MODE) return FILE_OPEN_STATUS;

procedure FILE_CLOSE (file F: FT);
procedure READ (file F: FT; VALUE: out TM);
procedure WRITE (file F: FT; VALUE: in TM);
procedure FLUSH (file F: FT);
function  ENDFILE (file F: FT) return BOOLEAN;

[...]

The first form of FILE_OPEN causes an error to occur if the second form of FILE_OPEN, when called under identical conditions,
would return a Status value other than OPEN_OK.

A call to FILE_OPEN of the first form is successful if and only if the call does not cause an error to occur. Similarly, a call
to FILE_OPEN of the second form is successful if and only if it returns a Status value of OPEN_OK.

The procedure FILE_OPEN, with parameters F, External_Name, and Status, is an overload of the form with parameters Status, F, External_Name,
and Open_Kind and implements the same behavior. The Open_Kind is always READ_MODE.

The procedure FILE_OPEN, with parameters F, External_Name, Open_Kind, and Status, is an overload of the form with parameters Status, F,
External_Name, and Open_Kind and implements the same behavior.

The impure function FILE_OPEN implements the same behavior as the procedure FILE_OPEN, with parameters F, External_Name, Open_Kind,
and Status. The procedure's output parameter Status of type FILE_OPEN_STATUS in the return value of the function.

[...]

(006c.2) 16.4 Package TEXTIO

package TEXTIO is
  -- Type definitions for text I/O:
  type LINE is access STRING; -- A LINE is a pointer to a STRING value.
  -- The predefined operations for this type are as follows:
  -- function"=" (anonymous, anonymous: LINE) return BOOLEAN;
  -- function"/=" (anonymous, anonymous: LINE) return BOOLEAN;
  -- procedure DEALLOCATE (P: inout LINE);
 
  [Editor note: Move LINE_VECTOR to std.STANDARD if LINE moves their.]
  type LINE_VECTOR is array(NATURAL range <>) of LINE;
  -- The predefined operations for this type are as follows:
  -- function "="(anonymous, anonymous: LINE_VECTOR) return BOOLEAN;
  -- function "/="(anonymous, anonymous: LINE_VECTOR) return BOOLEAN;
  -- function "&"(anonymous: LINE_VECTOR; anonymous: LINE_VECTOR) return LINE_VECTOR;
  -- function "&"(anonymous: LINE_VECTOR; anonymous: LINE) return LINE_VECTOR;
  -- function "&"(anonymous: LINE; anonymous: LINE_VECTOR) return LINE_VECTOR;
  -- function "&"(anonymous: LINE; anonymous: LINE) return LINE_VECTOR;
 
  type TEXT is file of STRING; -- A file of variable-length ASCII records.
  -- The predefined operations for this type are as follows:
  -- procedure FILE_OPEN (file F: TEXT; External_Name; in STRING; Open_Kind: in FILE_OPEN_KIND := READ_MODE);
  -- procedure FILE_OPEN (Status: out FILE_OPEN_STATUS; file F: TEXT; External_Name: in STRING; Open_Kind: in FILE_OPEN_KIND := READ_MODE);
  -- procedure FILE_CLOSE (file F: TEXT);
  -- procedure READ (file F: TEXT; VALUE: out STRING);
  -- procedure WRITE (file F: TEXT; VALUE: in STRING);
  -- procedure FLUSH (file F: TEXT);
  -- function ENDFILE (file F: TEXT) return BOOLEAN;
end package TEXTIO;

16.5 Standard environment package

(006c.3) 16.5.1 General [NEW headline level]

Package ENV contains declarations that provide a VHDL interface to the host environment.

use work.textio.all;

package ENV is
  procedure STOP (STATUS: INTEGER);
  procedure STOP;
  procedure FINISH (STATUS: INTEGER);
  procedure FINISH;
 
  function RESOLUTION_LIMIT return DELAY_LENGTH;
 
  [... LCS-2016-011 ...]
 
  type DIRECTORY_ITEMS is access LINE_VECTOR;
  -- The predefined operations for this type are as follows:
  -- function"=" (anonymous, anonymous: DIRECTORY_ITEMS) return BOOLEAN;
  -- function"/=" (anonymous, anonymous: DIRECTORY_ITEMS) return BOOLEAN;
  -- procedure DEALLOCATE (P: inout DIRECTORY_ITEMS);
 
  type DIRECTORY is record
    Name      : LINE;             -- current directory name; resolved to its canonical form
    Items     : DIRECTORY_ITEMS;  -- list of pointers to directory item names
  end record;
  -- The predefined operations for this type are as follows:
  -- function "="(anonymous, anonymous: DIRECTORY) return BOOLEAN;
  -- function "/="(anonymous, anonymous: DIRECTORY) return BOOLEAN;
  
  type DIR_OPEN_STATUS is (
    STATUS_OK,
    STATUS_NOT_FOUND,
    STATUS_NO_DIRECTORY,
    STATUS_ACCESS_DENIED,
    STATUS_ERROR
  );
  -- The predefined operations for this type are as follows:
  -- function "="(anonymous, anonymous: DIR_OPEN_STATUS) return BOOLEAN;
  -- function "/="(anonymous, anonymous: DIR_OPEN_STATUS) return BOOLEAN;
  -- function "<"(anonymous, anonymous: DIR_OPEN_STATUS) return BOOLEAN;
  -- function "<="(anonymous, anonymous: DIR_OPEN_STATUS) return BOOLEAN;
  -- function ">"(anonymous, anonymous: DIR_OPEN_STATUS) return BOOLEAN;
  -- function ">="(anonymous, anonymous: DIR_OPEN_STATUS) return BOOLEAN;
  -- function MINIMUM (L, R: DIR_OPEN_STATUS) return DIR_OPEN_STATUS;
  -- function MAXIMUM (L, R: DIR_OPEN_STATUS) return DIR_OPEN_STATUS;
  
  type DIR_CREATE_STATUS is (
    STATUS_OK,
    STATUS_ITEM_EXISTS,
    STATUS_ACCESS_DENIED,
    STATUS_ERROR
  );
  -- The predefined operations for this type are as follows:
  -- function "="(anonymous, anonymous: DIR_CREATE_STATUS) return BOOLEAN;
  -- function "/="(anonymous, anonymous: DIR_CREATE_STATUS) return BOOLEAN;
  -- function "<"(anonymous, anonymous: DIR_CREATE_STATUS) return BOOLEAN;
  -- function "<="(anonymous, anonymous: DIR_CREATE_STATUS) return BOOLEAN;
  -- function ">"(anonymous, anonymous: DIR_CREATE_STATUS) return BOOLEAN;
  -- function ">="(anonymous, anonymous: DIR_CREATE_STATUS) return BOOLEAN;
  -- function MINIMUM (L, R: DIR_CREATE_STATUS) return DIR_CREATE_STATUS;
  -- function MAXIMUM (L, R: DIR_CREATE_STATUS) return DIR_CREATE_STATUS;
  
  type DIR_DELETE_STATUS is (
    STATUS_OK,
    STATUS_NO_DIRECTORY,
    STATUS_NOT_EMPTY,
    STATUS_ACCESS_DENIED,
    STATUS_ERROR
  );
  -- The predefined operations for this type are as follows:
  -- function "="(anonymous, anonymous: DIR_DELETE_STATUS) return BOOLEAN;
  -- function "/="(anonymous, anonymous: DIR_DELETE_STATUS) return BOOLEAN;
  -- function "<"(anonymous, anonymous: DIR_DELETE_STATUS) return BOOLEAN;
  -- function "<="(anonymous, anonymous: DIR_DELETE_STATUS) return BOOLEAN;
  -- function ">"(anonymous, anonymous: DIR_DELETE_STATUS) return BOOLEAN;
  -- function ">="(anonymous, anonymous: DIR_DELETE_STATUS) return BOOLEAN;
  -- function MINIMUM (L, R: DIR_DELETE_STATUS) return DIR_DELETE_STATUS;
  -- function MAXIMUM (L, R: DIR_DELETE_STATUS) return DIR_DELETE_STATUS;
  
  type FILE_DELETE_STATUS is (
    STATUS_OK, 
    STATUS_NO_FILE,
    STATUS_ACCESS_DENIED,
    STATUS_ERROR
  );
  -- The predefined operations for this type are as follows:
  -- function "="(anonymous, anonymous: FILE_DELETE_STATUS) return BOOLEAN;
  -- function "/="(anonymous, anonymous: FILE_DELETE_STATUS) return BOOLEAN;
  -- function "<"(anonymous, anonymous: FILE_DELETE_STATUS) return BOOLEAN;
  -- function "<="(anonymous, anonymous: FILE_DELETE_STATUS) return BOOLEAN;
  -- function ">"(anonymous, anonymous: FILE_DELETE_STATUS) return BOOLEAN;
  -- function ">="(anonymous, anonymous: FILE_DELETE_STATUS) return BOOLEAN;
  -- function MINIMUM (L, R: FILE_DELETE_STATUS) return FILE_DELETE_STATUS;
  -- function MAXIMUM (L, R: FILE_DELETE_STATUS) return FILE_DELETE_STATUS;
  
  procedure       DIR_OPEN(Dir : out DIRECTORY; Path : in STRING; Status : out DIR_OPEN_STATUS);
  impure function DIR_OPEN(Dir : out DIRECTORY; Path : in STRING;) return DIR_OPEN_STATUS;        [Requires out parameters in impure functions: LCS 002 ??]
  procedure       DIR_CLOSE(Dir : in DIRECTORY);                                                 -- used to deallocate internal values
  
  impure function DIR_ITEMEXISTS(Path : in STRING) return BOOLEAN;
  impure function DIR_ITEMISDIR(Path : in STRING) return BOOLEAN;
  impure function DIR_ITEMISFILE(Path : in STRING) return BOOLEAN;
  
  procedure       DIR_WORKINGDIR(Path : in STRING; Status : out DIR_OPEN_STATUS);
  impure function DIR_WORKINGDIR(Path : in STRING) return DIR_OPEN_STATUS;
  impure function DIR_WORKINGDIR return STRING;
  
  procedure       DIR_CREATEDIR(Path : in STRING; Status : out DIR_CREATE_STATUS);
  procedure       DIR_CREATEDIR(Path : in STRING; Parents : in BOOLEAN; Status : out DIR_CREATE_STATUS);
  impure function DIR_CREATEDIR(Path : in STRING; Parents : in BOOLEAN := FALSE) return DIR_CREATE_STATUS;
  procedure       DIR_DELETEDIR(Path : in STRING; Status : out DIR_DELETE_STATUS);
  procedure       DIR_DELETEDIR(Path : in STRING; Recursive : in BOOLEAN; Status : out DIR_DELETE_STATUS);
  impure function DIR_DELETEDIR(Path : in STRING; Recursive : in BOOLEAN := FALSE) return DIR_DELETE_STATUS;
  procedure       DIR_DELETEFILE(Path : in STRING; Status : out FILE_DELETE_STATUS);
  impure function DIR_DELETEFILE(Path : in STRING) return FILE_DELETE_STATUS;
  
  constant        DIR_SEPARATOR : STRING;
end package ENV;

[Editor note: Three notes ...]

(006c.4) 16.5.2 Simulator API [NEW headline level]

Execution of the STOP procedures causes the same action by the host simulator as that caused by the vhpi_control function called with the argument
vhpiStop (see 23.5). Execution of the FINISH procedures causes the same action by the host simulator as that caused by the vhpi_control function
called with the argument vhpiFinish (see 23.5). Execution shall not return to the VHDL description after a call to the FINISH procedure. For the
procedures with the STATUS parameter, the value of the STATUS parameter may be used in an implementation defined manner by the host simulator. For the
procedures with no parameter, the effect is the same as that caused by the vhpi_control function with no additional arguments beyond the vhpiStop
or vhpiFinish argument.

The function RESOLUTION_LIMIT returns the value of the resolution limit (see 5.2.4.2).

16.5.3 Date and Time API [NEW, see LCS-2016-011]

[Editor note: See LCS-2016-011 Data and Time]

(006c.5) 16.5.4 Directory API [NEW]

All directory operations shall accept relative and absolute paths for parameter Path of type STRING, if Path is present as a parameter.

The procedure DIR_OPEN, with parameters Dir, Path and Status, returns a record of type DIRECTORY, which describes the directory and its directory items, for a given Path. The output
parameter Status of type DIR_OPEN_STATUS returns the result of the operation. The status shall be STATUS_OK on success, STATUS_NOT_FOUND if the path doesn't exist,
STATUS_NO_DIRECTORY if the path doesn't denote a directory, STATUS_ACCESS_DENIED if the privilege level is not sufficient and STATUS_ERROR
for any other error condition raised by the implementation. The predefined record type DIRECTORY has two elements:

  • Name references a STRING object, which contains the fully resolved absolute path of the represented directory.
  • Items references an array of LINE objects (type DIRECTORY_ITEMS), which in turn reference STRING objects. Each string object contains the simple name of a directory item
    in the directory.
In case of no success, the returned record contains null values for each record element.

The impure function DIR_OPEN implements the same behavior as the procedure DIR_OPEN, with parameters Dir, Path and Status. The procedure's output parameter Status of
type DIR_OPEN_STATUS in the return value of the function.

The impure function DIR_CLOSE, with parameter Dir, deallocates DIRECTORY objects allocated by DIR_OPEN.

The impure function DIR_ITEMEXISTS, with parameter Path, returns TRUE if the given path exists.

The impure function DIR_ITEMISDIR, with parameter Path, returns TRUE if the given path exists and is a directory.

The impure function DIR_ITEMISFILE, with parameter Path, returns TRUE if the given path exists and is a file.

The procedure DIR_WORKINGDIR, with parameters Path and Status, sets the working directory for all file operations using a relative path. The result of the operation
is returned by the out parameter Status of type DIR_OPEN_STATUS. The status shall have the same value for the same conditions as for procedure DIR_OPEN.

The impure function DIR_WORKINGDIR, with parameter Path, implements the same behavior as the procedure DIR_WORKINGDIR. The procedure's output parameter Status of type DIR_OPEN_STATUS
in the return value of the function.

The impure function DIR_WORKINGDIR, without parameters, is an overload and returns the current working directory used for all file operations as a STRING. The working
directory shall initially be the same as the tool's working directory.

The procedure DIR_CREATEDIR, with parameters Path and Status, creates the directory specified by parameter Path. The result of the operation is returned by the out
parameter Status of type DIR_CREATE_STATUS. The status shall be STATUS_OK on success, STATUS_ITEM_EXISTS if the path already exists, STATUS_ACCESS_DENIED if the privilege level is not
sufficient and STATUS_ERROR for any other error condition raised by the implementation.

The procedure DIR_CREATEDIR, with parameters Path, Parent and Status, has almost the same behavior as the former procedure. In addition, if parameter Parents is set to TRUE,
all missing intermediate directories are created as well, so Path can be created.

The impure function DIR_CREATEDIR implements the same behavior as the procedure DIR_CREATEDIR, with parameters Path, Parent and Status. The procedure's output parameter Status
of type DIR_CREATE_STATUS in the return value of the function.

The procedure DIR_DELETEDIR, with parameters Path and Status, deletes an empty directory specified by parameter Path. The result of the operation is return by the out parameter
Status of type DIR_DELETE_STATUS. The status shall be STATUS_OK on success, STATUS_NO_DIRECTORY if the Path is not a directory, STATUS_NOT_EMPTY if the directories is not empty,
STATUS_ACCESS_DENIED if the privilege level is not sufficient and STATUS_ERROR for any other error condition raised by the implementation.

The procedure DIR_DELETEDIR, with parameters Path, Recursive and Status, has almost the same behavior as the former procedure. In addition, if the parameter Recursive is set to TRUE,
the directory content is deleted recursively.

The impure function DIR_DELETEDIR implements the same behavior as the procedure DIR_DELETEDIR, with parameters Path, Recursive and Status. The procedure's output parameter Status of
type DIR_DELETE_STATUS in the return value of the function.

The function DIR_DELETEFILE, with parameters Path and Status, deletes the file specified by parameter Path. The result of the operation is returned by the out parameter Status of type
FILE_DELETE_STATUS. The status shall be STATUS_OK on success, STATUS_NO_FILE if the Path is not a directory, STATUS_ACCESS_DENIED if the privilege level
is not sufficient and STATUS_ERROR for any other error condition raised by the implementation.

The impure function DIR_DELETEFILE implements the same behavior as the procedure DIR_DELETEFILE, with parameters Path and Status. The procedure's output parameter Status of type
FILE_DELETE_STATUS in the return value of the function.

The deferred constant DIR_SEPARATOR of type STRING contains the path separator symbol used by the host system.

Comments

Version 1

Typo in DIRECTOTY_CHILDS

-- Hendrik Eeckhaut - 2017-01-23

Title is incorrect : "Language Change Specification for Hierarchical Libraries"

-- Hendrik Eeckhaut - 2017-01-23

Fixed typo and title. No version increment due to minor changes.

-- Patrick Lehmann - 2017-01-23

Would suggest changing "CHILD" to "ITEM" throughout.

-- Kevin Jennings - 2017-02-09

Version 2

Item is certainly better than child. However, the standard OS terminology would probably be entry.

The directory access interface relies on this DIRECTORY record. It is somewhat C-like containing the count of entries and a pointer to the data. However, it diverts from what C programmers would know from the POSIX and many other APIs. There you often have a set of functions like opendir, readdir, and closedir to implement the iteration over directory entries without ever constructing a potentially large, comprehensive list. Other languages (like Python) often use iterators for the very same incentive. I would also greatly favor an approach that does not have to construct this list.

If this record including a pointer to a comprehensive list of entries should find much approval, I am still wondering why the API record Directory needs to contain an explicit ItemCount. Wouldn't this be equivalent to Items.all'length? Also doing away with repeating the name of the queried directory would eliminate the need for the DIRECTORY record altogether. Without this record, even an API using a comprehensive list of entries can be based on returning a line_vector instead of inventing this other access type DirectoryItems.

-- Thomas Preusser - 2017-02-14

At first VHDL shall not provide a high level API for directories and files. This can be solved in an open source package.

At second, not all the world is build of old POSIX. There are other implementations available giving an abstract view to a directory. The directory name itself is included in my DIRECTORY structure because VHDL offers no way to get a handle to a parent directory. If can now be extracted by searching for the last delimiter sign. Not all directory APIs are iterator based. Most implementations of iterators on top of static information.

That brings me to third: POSIX internally works on a block structure which is returned by opendir! readdir is an iterator on top of that basic data structure.
https://linux.die.net/man/3/opendir
http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/dirstream.h;h=8303f07fab6f6efaa39e51411ef924e712d995e0;hb=fa39685d5c7df2502213418bead44e9543a9b9ec

-- Patrick Lehmann - 2017-02-14

Does DIRECTORY.Name repeat the path argument of the DIR_OPEN call used to retrieve it?

Is DIRECTORY.ItemCount the same as DIRECTORY.Items.all'length?

-- Thomas Preusser - 2017-02-15

Meeting 2017-02-16, resolved that ItemCount is redundant and can be removed.

-- Jim Lewis - 2017-02-17

Version 3

DIRECTORY.Name does not repeat the Path argument passed to DIR_OPEN. If Path is a relative path, the returned Name value returns a resolved value.

ItemCount is now removed.

-- Patrick Lehmann - 2017-02-17

1) There is small inconsistency. 16.5.1 defines procedures for DIR_CREATEDIR(...), DIR_DELETEDIR(...), and DIR_DELETEFILE(...) whereas 16.5.4 talks about functions with this name.

2) What is the rationale for having procedures instead of impure functions for DIR_WORKINGDIR(Path), DIR_CREATEDIR(...), DIR_DELETEDIR(...) and DIR_DELETEFILE(...)? All these subprograms have only one output parameter which can be a return value instead. This would also simplify the usage of these subprograms, e.g.

if DIR_CREATEDIR("test") /= STATUS_OK then report "Could not create directory." severity error; end if;

instead of

variable status : DIR_CREATE_STATUS;
...
DIR_CREATEDIR("test", status);
if status /= STATUS_OK then report "Could not create directory." severity error; end if;

-- Martin Zabel - 2017-02-17

Please, consider specifying DIRECTORY.Name as canonical path of the directory

  1. in DZ6.5.1 as the comment behind its declaration and
  2. in DZ6.5.4 in the respective bullet point.

Why does the second bullet point in DZ6.5.4 avoid the name LINE but instead talks about access types referencing STRING objects?

The statement If the parameter Recursive is set to TRUE, all subdirectories and files are deleted, even if the directory is not empty. is not sufficient. It should probably be stated that DIR_DELETEDIR will not delete a directory that is not empty unless the parameter Recursive is asserted, in which case all existing subitems will be deleted as well.

PS: Fixed some grammar.

-- Thomas Preusser - 2017-02-19

MZ: 1)
PL: Fixed that by defining overloads, see 2)

MZ: 2) What is the rationale for having procedures instead of impure functions ...
PL: The existing APIs in VHDL are using procedures to offer a status parameter (e.g. FILE_OPEN). Procedures allow us to map the Status parameter to open. I'm now providing overloads.

-- Patrick Lehmann - 2017-02-21

TBP: Please, consider specifying DIRECTORY.Name as canonical path of the directory
PL: Done

TBP: Why does the second bullet point in 16.5.4 avoid the name LINE ...
PL: Changed.

TBP: The statement [...] is not sufficient.
PL: Change the wording.

-- Patrick Lehmann - 2017-02-21

I think a mutable global working directory is problematic as it jeopardizes the isolation of modules.

I suggest to introduce a function PATH_CANONIZE(Path : STRING; Base : STRING :! ".") returns LINE= to canonize arbitrary paths, optionally relative to a specified base directory. This would also allow to drop the implied canonization of DIR_OPEN and help other file-related LCSs.

-- Thomas Preusser - 2017-02-21

TBP: I think a mutable global working directory is problematic as it jeopardizes the isolation of modules.
PL: VHDL has no modules. Please define what you exactly mean. The change of the working directory does not affect the location of source files or other simulator related files. Procedure DIR_WORKINGDIR only affects the file and directory API (FILE_* / DIR_*), nothing else.

TBP: I suggest to introduce a function PATH_CANONIZE(...) returns LINE [...]
A PATH_CANONIZE subprogram would require knowledge about symbolic links, mount points and junction points in the file system.

-- Patrick Lehmann - 2017-02-22

Version 5

PL: VHDL has no modules. Procedure DIR_WORKINGDIR only affects the file and directory API (FILE_* / DIR_*), nothing else.

TBP: So make it all the concurrent control flows that make up the simulation and want to use the file system API independently. A stateful system API (as thit one wrt. the working directory) hurts composability and reuse.

PL: A PATH_CANONIZE subprogram would require knowledge about symbolic links, mount points and junction points in the file system.

TBP: No, you just call the OS. For a weaker commitment, at least, allow to make a path absolute. This function is already included in OPEN_DIR, and Jim is about to provide a merged variant of retrieving the current file name as well. Factor it out to for reuse and simplification of the rest of the API.

-- Thomas Preusser - 2017-02-22

FILE_OPEN has status first. Read has valid flag last. I think DIR_OPEN, ... should have status as the first parameter following FILE_OPEN.

I am not excited about functions that return status and have something else as an out parameter. In general, I hate side-effects from function. They lead to "clever" code. I want "readable" code.

OTOH, the following code is growing on me. Note the boolean "OR" operator is a short circuit operator and the first one that returns TRUE (= STATUS_OK) is the last one that will be evaluated (at least so says the LRM:

AlertIfNot(DIR_OPEN(...) = STATUS_OK or DIR_OPEN(...) = STATUS_OK or DIR_OPEN(...) = STATUS_OK, 
                "Directory did not open", FAILURE) ; 

Is this really what you what? Keep in mind that each one can potentially update MyDir. -- Jim Lewis - 2017-02-24

To_string is also implicitly defined for all scalar values.

-- Jim Lewis - 2017-02-24

Why status should be first: WRT:

procedure DIR_CREATEDIR(Path : in STRING; Status : out DIR_CREATE_STATUS; Parents : in BOOLEAN := FALSE);

My preference is:

procedure DIR_CREATEDIR(Status : out DIR_CREATE_STATUS; Path : in STRING; Parents : in BOOLEAN := FALSE);

This follows the pattern of, acknowledging that out designates a target of an operation. Also acknowledging that when the line parameter is second the value is an input and when it is first it appends to the target:

procedure WRITE (file F: TEXT; VALUE: in STRING);
procedure FILE_OPEN (Status: out FILE_OPEN_STATUS; file F: TEXT;External_Name: in STRING;Open_Kind: in FILE_OPEN_KIND := READ_MODE);
procedure READLINE (file F: TEXT; L: inout LINE);
procedure WRITE (L: inout LINE; VALUE: in BIT;JUSTIFIED: in SIDE:= RIGHT; FIELD: in WIDTH := 0);

That leaves all versions of READ as the odd duck in the situation. What I see is that the READ was made consistent with WRITE, which also makes sense:

procedure READ (file F: TEXT; VALUE: out STRING);
procedure READ (L: inout LINE; VALUE: out BIT);
procedure READ (L: inout LINE; VALUE: out BIT_VECTOR;GOOD: out BOOLEAN);

OTOH, in a private conversation, you indicated that status could not be last, like read, due to the optional parameter. I disagree. One simply has to work harder on the authoring side, but it can be done, and I consider consistency of the use model most important:

procedure DIR_CREATEDIR(Path : in STRING; Parents : in BOOLEAN; Status : out DIR_CREATE_STATUS );
procedure DIR_CREATEDIR(Path : in STRING; Status : out DIR_CREATE_STATUS );

Back to functions, I don't feel great about them have generalized outputs, but I do like the use model of DIR_OPEN that I gave previously.

-- Jim Lewis - 2017-02-27

All the procedures and functions follow these rules:

  • first parameter is the altered object (Dir, File, Line, ...)
  • second parameter is the path
  • more parameters if needed
  • Status is the last parameter
  • Optional parameters might be the last parameters, due to language restrictions

I'm strictly against Status being the first parameter. Moreover I consider FILE_OPEN(Status ...) a design fault. And I don't want to redo a design fault just for consistency. If we look for other subprograms in VHDL, we'll see that status information is provided as the last parameter if no optional parameters are present.

-- Patrick Lehmann - 2017-02-28

Implemented optional parameters as procedure overloads to fulfill Jim's demands for coding style.

-- Patrick Lehmann - 2017-03-02

Version 6

@PL_02-28: Other than FILE_OPEN, what standard defined procedures return an enumerated value as status? What standard defined procedures return boolean as status?

@PL_03-02: Why do you think the definition order of FILE_OPEN a fault?

-- Jim Lewis - 2017-03-05

When you start a simulation running, some simulators move you to a directory other than the one in which you started. I think we may need a way to get the directory of some reference point, such as current vhdl code or tool starting directory, ???.

-- Jim Lewis - 2017-03-06

24 years ago, FILE_OPEN was introduced to VHDL. You have not provided any insight why it is bad and causing you so many issues.

I am big on consistency. Find a way to make things consistent. You could introduce a new overloaded FILE_OPEN, however, I think first you need to support why you think the current FILE_OPEN is the wrong pattern.

-- Jim Lewis - 2017-03-06

There is no consistency pattern, with only one existing subprogram in VHDL that has a status parameter of such form (plus one overload).

If we widen the scope and also look at READ subprograms, we see that the Good parameter is listed at the end of each subprogram, if present. This strengths my point of view. In addition, 6 reviewers of this LCS have no problem with my proposed interface.

There is no issue with the FILE_OPEN procedure except for that it does not apply to common rules how to order parameters in an interface as described in various books. Of cause these rules are not graved in stone, but I don't like to redo a design fault from VHDL-1993. I also like consistency, that's why I propose this interface. But, consistency is no excuse to redo design faults!

If you like, I can propose similar overloads for the existing file API. But this would require another LCS ...

-- Patrick Lehmann - 2017-03-06

Topic revision: r50 - 2017-07-23 - 22:33:51 - RobGaddi
 
Copyright © 2008-2021 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback