Page 1 of 2

ReadByte/ReadAsciiCharacter return value on error

Posted: Thu Apr 04, 2019 3:19 pm
by miskox
Manual says for ReadByte:

Code: Select all

Returns the read byte or zero if there was an error. 
and for ReadAsciiCharacter

Code: Select all

Returns the read ascii character or zero if there was an error. 
Shouldn't it return negative* value or value >255 if there is an error? But how could this value be returned (ReadByte has .b and ReadAsciiCharacter has .a type)?

Because byte read from the file can have a value of zero?

Thanks.
Saso

* don't see it as .b type (-128 to +127), only as a value between 0 and 255.

Re: ReadByte/ReadAsciiCharacter return value on error

Posted: Thu Apr 04, 2019 4:38 pm
by Sicro
Use Loc() to determine whether ReadByte() was successful:

Code: Select all

If CreateFile(0, GetTemporaryDirectory() + "test")
  For i = 1 To 10
    WriteByte(0, i)
  Next
  FileSeek(0, 0)
  
  Repeat
    oldPos = Loc(0)
    value = ReadByte(0)
    newPos = Loc(0)
    If oldPos <> newPos
      Debug value
    Else
      Debug "ReadByte: Error"
      Break
    EndIf
  ForEver
  
  CloseFile(0)
Else
  Debug "File could not be created!"
EndIf

Re: ReadByte/ReadAsciiCharacter return value on error

Posted: Fri Apr 05, 2019 7:16 am
by miskox
Thanks for the solution but the problem remains - return value should be returned correctly. I think that the application should just rely on 'errorlevel'* and should not include ten, hundred, thousands of lines of code to do the errorchecking.

Saso
* return value whatever we call it

Re: ReadByte/ReadAsciiCharacter return value on error

Posted: Fri Apr 05, 2019 2:45 pm
by Sicro
miskox wrote:Thanks for the solution but the problem remains
Of course, only the PureBasic developers can change that. We can only create workarounds.
miskox wrote:I think that the application should just rely on 'errorlevel'* and should not include ten, hundred, thousands of lines of code to do the errorchecking.
You're exaggerating. :wink: The error checking code is very small in this case.
Shouldn't it return negative* value or value >255 if there is an error? But how could this value be returned (ReadByte has .b and ReadAsciiCharacter has .a type)?
Because byte read from the file can have a value of zero?
The problem is that the function returns only one value and the value range is already exhausted and therefore no more value can be reserved for an error. You already realized that. Using a value outside the valid value range of the return type is not a good idea, because the value swaps when an overflow occurs:

Code: Select all

value.b = 127+1 ; Value is over valid value range (byte: -128 to +127)
Debug value ; -128 -- No error recognizable, because the value is in the valid value range
It would probably be best if the read functions had one more parameter to which you could pass an address to a variable that receives the error code:

Code: Select all

value = ReadByte(file, @error)
If error = #False
  Debug value
Else
  Debug "Error"
EndIf
Or a new function:

Code: Select all

value = ReadByte(file)
If GetLastFileError(file) = #PB_FileError_None
  Debug value
Else
  Debug "Error"
EndIf
We can discuss which variant is better and then create a feature request.

Re: ReadByte/ReadAsciiCharacter return value on error

Posted: Fri Apr 05, 2019 3:37 pm
by mk-soft
I don't see any problems here.

It only depends on how the value is viewed. Signed or Unsigned.
PB have the var type ASCII (var.a) and UNICODE (var.u)
The type var.a is the same as Unsigned Byte and the type var.u the same as unsigned word. PB also sees this as unsigned.

Code: Select all

Define var1.a = 254

If var1 >= 128
  Debug "Ok"
EndIf

Define var2.u = 40000

If var2 >= 32768
  Debug "ok"
EndIf
So there is not much to do to read the file as byte array (Unsigned).

Code: Select all

Macro ReadUnsignedByte(File)
  ReadAsciiCharacter(File)
EndMacro

Macro ReadUnsignedWord(File)
  ReadUnicodeCharacter(File)
EndMacro

Dim UnsignedByte.a(20)
cnt = 0
file.s = OpenFileRequester("Open Any File", "", "", 0)
If Bool(file)
  If ReadFile(0, file)
    While Not Eof(0) And cnt <= 20
      old_loc = Loc(0)
      UnsignedByte(cnt) = ReadUnsignedByte(0)
      If Loc(0) <= old_loc
        Debug "Error read byte"
        Break
      EndIf
      cnt + 1
    Wend
  EndIf
  ; Output
  For index = 0 To cnt - 1
    Debug "Index " + index + " = " + UnsignedByte(index)
  Next
EndIf

Re: ReadByte/ReadAsciiCharacter return value on error

Posted: Fri Apr 05, 2019 7:00 pm
by Sicro
@mk-soft:
The topic here is not about signed/unsigned bytes. The point is that the ReadByte() function in the PB help says that in the case of an error, the zero value is returned:
PB help => ReadByte() wrote:Returns the read byte or zero if there was an error.
However, the zero value is not always an error, but can also be a normal value.

So I showed the thread creator a workaround that uses Loc() to determine whether ReadByte() was successful or not. But the thread creator thinks that the workaround code is too much code and checking whether ReadByte() was successful or not should be easier.

Re: ReadByte/ReadAsciiCharacter return value on error

Posted: Fri Apr 05, 2019 9:07 pm
by Josh
@ miskox:

A ReadByte can only return a variable of type Byte. So it doesn't matter which value is returned, because every read value can occur in the file.

You just have to make sure that you don't read beyond the end of the file. Shouldn't be too complicated.

Code: Select all

CreateFile (0, GetTemporaryDirectory() + "test")

For i = 1 To 10
  WriteByte (0, i)
Next
FileSeek (0, 0)

While Not Eof(0)
  Debug ReadByte (0)
Wend

Re: ReadByte/ReadAsciiCharacter return value on error

Posted: Sat Feb 15, 2020 4:09 pm
by Tristano
@miskox is right, I also found the error return description in the Documentation quite confusing, and had to search the forum to work out how it works.

@Sicro, thanks for the solution, I wouldn't have thought of it.

So, on the one hand the Documentation is correct when it mentions that it always returns 0 in case of error; what it doesn't clarify is how to distinguish when a returned 0 is an error or just the read value.

I like @Sicro proposal for a new feature that adds a GetLastFileError(file) command to check if the last file operation for any given file was successful or encountered an error — it would be similar to C's ferror(FILE *stream) function. Defintely, it would spare all the workaround code doing all the Loc() checks, and keep the code more readable.

I'll create a post and add it to the new features wishlist!

Re: ReadByte/ReadAsciiCharacter return value on error

Posted: Sat Feb 15, 2020 4:22 pm
by Tristano
Submitted a new feature request for the GetLastFileError(file) command proposed by @Sicro:

viewtopic.php?f=3&t=74627

Re: ReadByte/ReadAsciiCharacter return value on error

Posted: Sun Feb 16, 2020 2:15 am
by BarryG
I agree with miskox. ReadByte() shouldn't blindly return 0 for error because binary files have 0 in them. How will we know if 0 was the actual data byte read, or an error?

Workarounds are nice but not the solution, because the fact remains that ReadByte() is fundamentally flawed, and needs fixing to return a different value for a read error. This should be -1, because no file has a byte value of -1 (as seen in any hex editor: all byte values are $00 to $FF).

Re: ReadByte/ReadAsciiCharacter return value on error

Posted: Sun Feb 16, 2020 7:52 am
by #NULL
-1 in a byte.b is $ff.
There is no fix via a different return value, you need a different error handling strategy.

Re: ReadByte/ReadAsciiCharacter return value on error

Posted: Sun Feb 16, 2020 8:00 am
by #NULL
#NULL wrote:There is no fix via a different return value, you need a different error handling strategy.
PB could pack the value byte and an error byte together in a long or quad and the user can then extract them with a bit mask again, but I already see the bug reports coming even if it would be documented.

Re: ReadByte/ReadAsciiCharacter return value on error

Posted: Sun Feb 16, 2020 9:18 am
by Josh
I am always shocked that it is so difficult to read and interpret a text by some people.

Sure, the help is not perfect, but what is so difficult to understand about the sentence 'Returns the read byte or zero if there was an error'? I can't see anywhere in the help something like 'If zero is returned, an error was a detected'. And excuse me, if someone thinks that a return value of -1 or any other value will change something, then there is much more he hasn't understood.


If you want a check for errors, few lines of code are required, no matter if Pb adds some additional functions or not. Check for the end of the file and all is fine. Of course, there are plenty of other ways to check for the end of a file, but that depends on the file you are working on and you have to know how the file is structured.

What Pb might do better is that with the 'Loc' always the calculated value is returned after a read access, so this value is not terminated with 'Lof'. Then you can check afterwards if the file was read over the end of the file.

Re: ReadByte/ReadAsciiCharacter return value on error

Posted: Sun Feb 16, 2020 12:56 pm
by BarryG
Josh wrote:what is so difficult to understand about the sentence 'Returns the read byte or zero if there was an error'? I can't see anywhere in the help something like 'If zero is returned, an error was a detected'.
You do realize that "zero if there was an error" and "if zero is returned, an error was a detected" mean the same thing, right? So yes, the help does say that. You just quoted it.

Re: ReadByte/ReadAsciiCharacter return value on error

Posted: Sun Feb 16, 2020 1:25 pm
by Josh
Barry, that's the problem. Something is interpreted from a sentence that is simply not true, fragments are torn out from a sentence that completely ignore the context. Why you don't write the whole sentence as it appears in the help? Maybe because then your argument won't hold up from the start?

If 'Returns the read byte or zero if there was an error' means the same thing to you as 'If zero is returned, an error was a detected', then I feel sorry for you. The same bullshit as your claim that a byte value in a file cannot contain -1.