Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2019-03

Publish some of FPC's internal cross-platform functionality

17 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Anton Shepelev

Hello, all

FreePascal has many low-level cross-platform functions scattered over multiple .inc files but not consolilated into reusable cross-platform units. Consider, for example, the functions

  function do_read (h: longint; addr: pointer; len: longint) : longint;
  function do_write(h: longint; addr: pointer; len: longint) : longint;

implemented in sysfile.inc for Unix, Winows, Mac OS, MS-DOS, and other operatring systems. Wouldn't it be useful to publish them in a unit sysfile.pp, possibly along with a facility to translate the OS-specific error codes into a general enumeration?

It would relieve the programmer of writing conditionally compiled OS-specific code sections for such basic operations as are already implemented in FreePascal's internals. I, for example, have to do it whenever my Windws/Unix program works with a file handle.

Please, do not forward replies to my e-mail.

Reply by email

Michael Van Canneyt
to Anton Shepelev
Anton Shepelev wrote 21 lines
Hello, all FreePascal has many low-level cross-platform functions scattered over multiple .inc files but not consolilated into reusable cross-platform units. Consider, for example, the functions function do_read (h: longint; addr: pointer; len: longint) : longint; function do_write(h: longint; addr: pointer; len: longint) : longint; implemented in sysfile.inc for Unix, Winows, Mac OS, MS-DOS, and other operatring systems. Wouldn't it be useful to publish them in a unit sysfile.pp, possibly along with a facility to translate the OS-specific error codes into a general enumeration? It would relieve the programmer of writing conditionally compiled OS-specific code sections for such basic operations as are already implemented in FreePascal's internals. I, for example, have to do it whenever my Windws/Unix program works with a file handle.

I don't think we should publish this, it forces us to maintain this interface.

I also don't see why you need this.
You have this functionality available in a cross-platform manner in THandleStream, or the sysutils functions.

Michael.

Reply by email

Sven Barth
to Anton Shepelev: Hello, all FreePascal has many low-level cross-platform functions scattered over multiple…

Anton Shepelev schrieb am Sa., 9. März 2019, 18:09:

Show quoted text 6 lines
It would relieve the programmer of writing conditionally compiled OS-specific code sections for such basic operations as are already implemented in FreePascal's internals. I, for example, have to do it whenever my Windws/Unix program works with a file handle.

Use the already published interfaces for that, after all that's the reason why those functions are there at all (for this specific case it would be FileRead/FileWrite).

Otherwise I agree with Michael. Publishing them directly means maintaining them.

Regards,
Sven

Reply by email

Anton Shepelev
to Michael Van Canneyt: I don't think we should publish this, it forces us to maintain this interface. I also…

Michael Van Canneyt to Anton Shepelev:

Show quoted text 7 lines
> function do_read (h: longint; addr: pointer; len: > longint) : longint; function do_write(h: longint; addr: > pointer; len: longint) : longint; I also don't see why you need this. You have this functionality available in a cross-platform manner in THandleStream, or the sysutils functions.

THandleStream is out of the question because I don't do OOP, but the functions FileRead and FileWrite in SysUtils will indeed suffice for most of my use cases, thanks.

I don't understand, however, how to employ them for my current task of writing a TextRec driver for a custom file handle. The standard routines report errors by setting the InOutRes variable from the OS-specific error code via OS- specific translation function Errno2InoutRes, which is not published, whereas FileRead and FileWrite return -1 on any error. What shall I assign to InOutRes when one of them fails? Maybe they should be extended to set InOutRes in addition to returning -1?

Or is there already a way to initialise a Text variable with a user-supplied THandle?

Please, do not forward replies to my e-mail.

Reply by email

Michael Van Canneyt
to Anton Shepelev
Anton Shepelev wrote 23 lines
Michael Van Canneyt to Anton Shepelev: > > function do_read (h: longint; addr: pointer; len: > > longint) : longint; function do_write(h: longint; addr: > > pointer; len: longint) : longint; > > I also don't see why you need this. You have this > functionality available in a cross-platform manner in > THandleStream, or the sysutils functions. THandleStream is out of the question because I don't do OOP, but the functions FileRead and FileWrite in SysUtils will indeed suffice for most of my use cases, thanks. I don't understand, however, how to employ them for my current task of writing a TextRec driver for a custom file handle. The standard routines report errors by setting the InOutRes variable from the OS-specific error code via OS- specific translation function Errno2InoutRes, which is not published, whereas FileRead and FileWrite return -1 on any error. What shall I assign to InOutRes when one of them fails? Maybe they should be extended to set InOutRes in addition to returning -1?

For these functions, you can get more info with GetLastOSError, and use that to set InOutRes.

Michael.

Reply by email

Anton Shepelev
to Marco van de Voort

Marco van de Voort:

Really? So why can't you simply use untyped "file"?

I am writing a TextRec driver that shall work with a bare THandle, e.g.:

Program Test;
uses TextDrv, SysUtils;
var
   t: Text;
   s: AnsiString;
   h: THandle;
begin
   h := FileOpen( 'C:\test.txt', fmOpenRead );
   FdAsText( t, h );
   while not Eof( t ) do
   begin
      ReadLn( t, s );
      WriteLn( s );
   end;
   Close( t );
end.
Please, do not forward replies to my e-mail.

Reply by email

Anton Shepelev
to Michael Van Canneyt: For these functions, you can get more info with GetLastOSError, and use that to set…

Michael Van Canneyt about FileWrite and FileRead:

For these functions, you can get more info with GetLastOSError, and use that to set InOutRes.

Thank you, but how do I translate the return value of GetLastOSError into a value of InOutRes? The translation functions are privately implemented in sysos.inc .

Please, do not forward replies to my e-mail.

Reply by email

Marco van de Voort
to Anton Shepelev: Marco van de Voort: I am writing a TextRec driver that shall work with a bare THandle,…

Op 2019-03-09 om 21:45 schreef Anton Shepelev:

Show quoted text 5 lines
Marco van de Voort: > Really? So why can't you simply use untyped "file"? I am writing a TextRec driver that shall work with a bare THandle, e.g.:

Use (objpas.) fileread and filewrite

https://www.freepascal.org/docs-html/3.0.4/rtl/sysutils/fileread.html

https://www.freepascal.org/docs-html/3.0.4/rtl/sysutils/filewrite.html

which is what these internal routines are the undocument interface for anyway.

Reply by email

Michael Van Canneyt
to Anton Shepelev: Michael Van Canneyt about FileWrite and FileRead: Thank you, but how do I translate the…
Anton Shepelev wrote 8 lines
Michael Van Canneyt about FileWrite and FileRead: > For these functions, you can get more info with > GetLastOSError, and use that to set InOutRes. Thank you, but how do I translate the return value of GetLastOSError into a value of InOutRes? The translation functions are privately implemented in sysos.inc .

You can copy them. It is open source, after all.

It's not a sin to copy such things.

Michael.

Reply by email

Anton Shepelev
to Michael Van Canneyt

Michael Van Canneyt to Anton Shepelev:

Show quoted text 6 lines
> Thank you, but how do I translate the return value of > GetLastOSError into a value of InOutRes? The > translation functions are privately implemented in > sysos.inc . You can copy them. It is open source, after all.

Which brings us back to the initial problem of having to write conditionally compiled code for something that FreePascal already implements internally in a cross-platform manner.

Since we already have cross-platform functions FileRead and FileWrite, would not it be useful to have them set the InOutRes variable, or to publish a facility for converting the value of GetLastOSError into an InOutRes value?

Please, do not forward replies to my e-mail.

Reply by email

Sven Barth
to Anton Shepelev
Anton Shepelev wrote 16 lines
Michael Van Canneyt to Anton Shepelev: >> Thank you, but how do I translate the return value of >> GetLastOSError into a value of InOutRes? The >> translation functions are privately implemented in >> sysos.inc . > You can copy them. It is open source, after all. Which brings us back to the initial problem of having to write conditionally compiled code for something that FreePascal already implements internally in a cross-platform manner. Since we already have cross-platform functions FileRead and FileWrite, would not it be useful to have them set the InOutRes variable, or to publish a facility for converting the value of GetLastOSError into an InOutRes value?

The usage of InOutRes is only defined for the Pascal style file I/O (Read/Write).

Regards,
Sven

Reply by email

Anton Shepelev
to Sven Barth

Sven Barth to Anton Shepelev:

Show quoted text 7 lines
>Since we already have cross-platform functions FileRead >and FileWrite, would not it be useful to have them set the >InOutRes variable, or to publish a facility for converting >the value of GetLastOSError into an InOutRes value? The usage of InOutRes is only defined for the Pascal style file I/O (Read/Write).

Thanks for the correction. My second propostion, however, still holds. Writers of drivers for this Pascal-style I/O interface should have the ability to convert OS-specific error codes into InOurRes values, which are not even documented at:

https://www.freepascal.org/docs-html/rtl/system/inoutres.html

Notice also that FreePascal's TextRec handling is
incompatible with that of Delphi. The TextRec operations OpenFunc, InOutFunc, FlushFunc, and CloseFunc return a longint, which Delphi interprets as the result code but FreePascal ignores. Therefore, I must set InOutRes in FreePascal and return the error in Delphi.

Please, do not forward replies to the list to my e-mail.

Reply by email

Sven Barth
to Anton Shepelev

Anton Shepelev schrieb am Mo., 11. März 2019, 15:12:

Show quoted text 17 lines
Sven Barth to Anton Shepelev: >>Since we already have cross-platform functions FileRead >>and FileWrite, would not it be useful to have them set the >>InOutRes variable, or to publish a facility for converting >>the value of GetLastOSError into an InOutRes value? > >The usage of InOutRes is only defined for the Pascal style >file I/O (Read/Write). Thanks for the correction. My second propostion, however, still holds. Writers of drivers for this Pascal-style I/O interface should have the ability to convert OS-specific error codes into InOurRes values, which are not even documented at: https://www.freepascal.org/docs-html/rtl/system/inoutres.html

You're not supposed to use InOutRes directly to read it (that should probably be added to its documentation) , but instead IOResult needs to be used. And *there* the values are documented:
https://www.freepascal.org/docs-html/rtl/system/ioresult.html

Notice also that FreePascal's TextRec handling is

Show quoted text 6 lines
incompatible with that of Delphi. The TextRec operations OpenFunc, InOutFunc, FlushFunc, and CloseFunc return a longint, which Delphi interprets as the result code but FreePascal ignores. Therefore, I must set InOutRes in FreePascal and return the error in Delphi.

Now *that* is something that can and probably also should be talked about.

Regards,
Sven

Reply by email

Anton Shepelev
to Sven Barth

Sven Barth to Anton Shepelev:

Show quoted text 10 lines
> Writers of drivers for this Pascal-style I/O interface > should have the ability to convert OS-specific error > codes into InOurRes values, which are not even > documented at: > > https://www.freepascal.org/docs-html/rtl/system/inoutres.html You're not supposed to use InOutRes directly to read it (that should probably be added to its documentation) , but instead IOResult needs to be used.

But I am talking about writing to InOutRes in order to indicate an error condition from one of the TextRec operations, because FreePascal ignores the return value of those functions.

Show quoted text 9 lines
> Notice also that FreePascal's TextRec handling is > incompatible with that of Delphi. The TextRec > operations OpenFunc, InOutFunc, FlushFunc, and CloseFunc > return a longint, which Delphi interprets as the result > code but FreePascal ignores. Therefore, I must set > InOutRes in FreePascal and return the error in Delphi. Now *that* is something that can and probably also should be talked about.

OK. system.inc defines FileFunc as a procedure without a return value:

   FileFunc = Procedure(var t : TextRec);

whereas streamio.pp defines the same operations as functions returning longint, e.g.:

   Function StreamRead(var F: TTextRec) : longint;

and reports errors through the return value, which is ignored in text.inc . Not so in Delphi, where the internal mechanism forwards the return value to IOResult, relieving the driver writer of setting it manually.

In addition to system.inc and text.inc, a patch will modify all platform-specfic files that implement the TextRec operations and set InOutRes. Many of them already use the return value for the size of data read or written, but one could use negative values to encode errors. text.inc would then:

   procedure FileReadFunc( var t:TextRec ): LongInt;
   var fres: LongInt;
   begin
      fres := do_read( f.Handle, f.Bufptr, f.BufSize );
      if fres < 0 then { fres has a negative IOResult value. }
      begin
         result := -fres; exit;
      end;
      result   := 0; { Success }
      t.BufEnd := fres;
      t.BufPos := 0;
   end;

and will check the return value of every TextRec operation.

Please, do not forward replies to my e-mail.

Reply by email

Anton Shepelev
to Anton Shepelev
Show quoted text 47 lines
> > Notice also that FreePascal's TextRec handling is > > incompatible with that of Delphi. The TextRec > > operations OpenFunc, InOutFunc, FlushFunc, and CloseFunc > > return a longint, which Delphi interprets as the result > > code but FreePascal ignores. Therefore, I must set > > InOutRes in FreePascal and return the error in Delphi. > Sven Barth: > Now *that* is something that can and probably also should > be talked about. OK. system.inc defines FileFunc as a procedure without a return value: FileFunc = Procedure(var t : TextRec); whereas streamio.pp defines the same operations as functions returning longint, e.g.: Function StreamRead(var F: TTextRec) : longint; and reports errors through the return value, which is ignored in text.inc . Not so in Delphi, where the internal mechanism forwards the return value to IOResult, relieving the driver writer of setting it manually. In addition to system.inc and text.inc, a patch will modify all platform-specfic files that implement the TextRec operations and set InOutRes. Many of them already use the return value for the size of data read or written, but one could use negative values to encode errors. text.inc would then: procedure FileReadFunc( var t:TextRec ): LongInt; var fres: LongInt; begin fres := do_read( f.Handle, f.Bufptr, f.BufSize ); if fres < 0 then { fres has a negative IOResult value. } begin result := -fres; exit; end; result := 0; { Success } t.BufEnd := fres; t.BufPos := 0; end; and will check the return value of every TextRec operation.

( should be `function' instead of `procedure' )

Will the developers consider such a patch, or are these deviations from Delphi intentional?

Please, do not forward replies to the list to my e-mail.

Reply by email

Anton Shepelev
to Anton Shepelev
Show quoted text 9 lines
system.inc defines FileFunc as a procedure without a return value: FileFunc = Procedure(var t : TextRec); whereas streamio.pp defines the same operations as functions returning longint, e.g.: Function StreamRead(var F: TTextRec) : longint;

Here are the relevant fragments from the Turbo Pascal Language Reference
(http://turbopascal.org/files/Turbo_Pascal_Version_7.0_Language_Guide_1992.pdf):

The four functions that define each device driver are Open, InOut, Flush, and Close. The function header of each function is:

      function DeviceFunc(var F: TTextRec): Integer;
   [...]  The return value of a device-interface function
   becomes the value returned by IOResult.  If the return
   value is zero, the operation was successful.

compare it with FreePascal's defintion:

   FileFunc = Procedure(var t : TextRec);

It is not withtout a reason that the type is called FileFunc instead of FileProc, and both TurboPascal and Delphi analyse the return value.

The document goes on:

The Flush function is called at the end of each Read, Readln, Write, and Writeln. It can optionally flush the text file buffer.

Whereas in FreePascal Flush is not called in read mode.

Please, do not forward replies to my e-mail.

Reply by email