Using "PRINT #" and "INPUT ()" on binary files

General FreeBASIC programming questions.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Using "PRINT #" and "INPUT ()" on binary files

Post by MrSwiss »

Yes, I've also noted, that someone must have been "diddling", with the forum SW.
(just check the massively increased "max. users online on date", was at "201")
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Using "PRINT #" and "INPUT ()" on binary files

Post by fxm »

Normally Get#/Put# should be used with Open For Binary, and [Line] Input#/Input()/Print# with textual Open For Input/Output.
I already noticed that binary access mode is also compatible with Print#, [Line] Input # and Input() (viewtopic.php?p=218697#p218697).
But this is not currently a requirement (not in the documentation) and therefore we can not guarantee that this will always be true for future versions of fbc.
angros47
Posts: 2324
Joined: Jun 21, 2005 19:04

Re: Using "PRINT #" and "INPUT ()" on binary files

Post by angros47 »

Actually, for PRINT # documantation says:
filenum
The file number of a file or device opened for Output or Append.
For INPUT #
Reads from a text file through a bound file number a delimiter-separated set of values
and LINE INPUT #:
Reads a line from an open text file (opened for Input through a bound file number)
For INPUT()
Reads a number of characters from the console, or a bound file/device specified by filenum
So, while in the first three cases documentation states explicitly to use a text file (although it seems to work also in binary files), there is no such a requirement in the last case.
angros47
Posts: 2324
Joined: Jun 21, 2005 19:04

Re: Using "PRINT #" and "INPUT ()" on binary files

Post by angros47 »

Ok, found it... in the original Quick Basic help file:
INPUT$ Function Details

Syntax
INPUT$(n[,[#]filenumber])

The n is the number of characters (bytes) to read from the file. The
filenumber is the number used to open the file.

If the file is opened for random access, the argument n must be less
than or equal to the record length set by the LEN clause in the OPEN
statement (or less than or equal to 128 if the record length is not
set). If the given file is opened for binary or sequential access,
then n must be less than or equal to 32,767.

If the filenumber is not specified, the characters are read from the
standard input device. (If input has not been redirected, the keyboard
is the standard input device).

You can use the DOS redirection symbols " "(<, >, or >>) or the pipe
symbol (|) to redefine the standard input or standard output for an
executable file created with BASIC. (See your operating system
manual for a complete discussion of redirection and pipes.)

No characters are echoed on the screen. All control characters are
passed through except CTRL+BREAK, which interrupts execution
of the function.
So, I guess Input() is required to work in binary files, even in future versions, if FreeBasic follows the same design
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Using "PRINT #" and "INPUT ()" on binary files

Post by dodicat »

dev_file_open.c looks like one of the main (file device) files in the rtl source.
Mostly the "b" string (binary) is used
e.g.
case FB_FILE_MODE_OUTPUT:
/* will create the file if it doesn't exist */
openmask = "wb";
break;

I think the b is always recommended for windows.
I am unsure if the rtl concerning files is still similar to quickbasic, or has been changed over the years, so that's about all I can offer in this thread.
Imortis
Moderator
Posts: 1924
Joined: Jun 02, 2005 15:10
Location: USA
Contact:

Re: Using "PRINT #" and "INPUT ()" on binary files

Post by Imortis »

MrSwiss wrote:OK, you seem to be someone, that wants: "to go through a wall, head first".

Print #, and Input() are meant for NONE "binary" file I/O (all else is pure speculation).
You're probably likely, to end up with the face in the mud ...
Please keep these kinds of comments to a minimum. This has been reported as a possible "personal attack" and I can see that. I assume that this is not the case and it is just a figure of speech that does not translate well.
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Using "PRINT #" and "INPUT ()" on binary files

Post by fxm »

angros47 wrote:Ok, found it... in the original Quick Basic help file:
INPUT$ Function Details

Syntax
INPUT$(n[,[#]filenumber])

The n is the number of characters (bytes) to read from the file. The
filenumber is the number used to open the file.

If the file is opened for random access, the argument n must be less
than or equal to the record length set by the LEN clause in the OPEN
statement (or less than or equal to 128 if the record length is not
set).
...
So, I guess Input() is required to work in binary files, even in future versions, if FreeBasic follows the same design
Indeed, I see this in the QB documentation, but by cons nothing about compatibility of 'Print#' and '[Line] Input#' with 'Random/Binary' files.

If the developers agree to maintain the current compatibility of 'Input(n As Integer, filenum As Integer) As String' (with 'Random/Binary' files) in the future versions, I can then complete the corresponding page of the FB documentation.
coderJeff
Site Admin
Posts: 4326
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Using "PRINT #" and "INPUT ()" on binary files

Post by coderJeff »

fxm wrote:If the developers agree to maintain the current compatibility of 'Input(n As Integer, filenum As Integer) As String' (with 'Random/Binary' files) in the future versions, I can then complete the corresponding page of the FB documentation.
Without actually testing every mode on every target platform, here's what I think I can say, with some amount of confidence:

1) GET/PUT/SEEK position argument is by file byte offset, except for RANDOM mode files/devices which is by record number, and depends on record length.
2) GET/PUT will write/read exact bytes only in all modes, except RANDOM which will GET/PUT records
3) PRINT will write strings, subject to CR/CR+LF translation depending on platorm & file mode
4) INPUT # will read strings, subject to CR/CR+LF translataion (shouldn't matter in fb), and delimiters
5) INPUT() will read bytes, similar to GET #
6) Exact device may matter, i.e. file versus COM versus LPT, etc, especially on DOS/WIN where we have written special drivers for each kind of device. On linux, maybe not so much, since most stream operations resolve to C runtime calls.

I'll be honest; I have not tested any claims or behaviours presented in this thread. I'm just commenting on the topic from what (I think) I remember. I know in the past there have been differences between original QB(TM) and freebasic behaviours, especially when it comes to RANDOM files and EOF, etc.
angros47
Posts: 2324
Joined: Jun 21, 2005 19:04

Re: Using "PRINT #" and "INPUT ()" on binary files

Post by angros47 »

I verified for sure that, at least under Windows and DOS (not under Linux, at least in my test) GET# and INPUT() produce different results (and they may also change the position in different ways) if the file has been opened FOR INPUT or FOR BINARY
coderJeff
Site Admin
Posts: 4326
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Using "PRINT #" and "INPUT ()" on binary files

Post by coderJeff »

Ah, I see what you are talking about now. dodicat was pretty close. files opened for INPUT are opened with "rt" mode (read, text). GET# and INPUT(), ultimately call fread() in the c runtime. According to windows docs, fread(), when used with files opened in text mode files, CR's are replaced with CR+LF's pairs. Normally, the opposite would occur for OUTPUT, which uses fwrite(), but fbc opens files for APPEND and OUTPUT in c runtime binary mode only.

Here's a test program with output (from windows).

Code: Select all

sub PrintStringAsHex( t as string, s as string )
	print left( t & space(20), 20 );
	for i as integer = 1 to len(s)
		print hex( asc(mid(s, i, 1)), 2 ); " ";
	next
	print
end sub

sub ReadFileContents()

	dim s as string

	open "test.txt" for binary as #1
	s = string( lof(1), 0 )
	get #1,, s
	PrintStringAsHex( "binary+get", s )
	close #1

	open "test.txt" for binary as #1
	s = input( lof(1), #1 )
	PrintStringAsHex( "binary+input()", s )
	close #1

	open "test.txt" for input as #1
	s = string( lof(1), 0 )
	get #1,, s
	PrintStringAsHex( "input+get", s )
	close #1

	open "test.txt" for input as #1
	s = input( lof(1), #1 )
	PrintStringAsHex( "input+input()", s )
	close #1

end sub


dim s as string

open "test.txt" for binary as #1
s = "free" + chr(13, 10) + "basic" + chr(13, 10)
put #1,,s
PrintStringAsHex( "binary+put", s )
close #1

ReadFileContents()

print

open "test.txt" for output as #1
s = "free" + chr(13) + "basic" + chr(13)
put #1,,s
PrintStringAsHex( "output+put", s )
close #1

ReadFileContents()

print

open "test.txt" for output as #1
s = "free" + chr(13) + "basic" + chr(13)
print #1,s;
PrintStringAsHex( "output+print", s )
close #1

ReadFileContents()
OUTPUT:

Code: Select all

binary+put          66 72 65 65 0D 0A 62 61 73 69 63 0D 0A
binary+get          66 72 65 65 0D 0A 62 61 73 69 63 0D 0A
binary+input()      66 72 65 65 0D 0A 62 61 73 69 63 0D 0A
input+get           66 72 65 65 0A 62 61 73 69 63 0A 00 00
input+input()       66 72 65 65 0A 62 61 73 69 63 0A

output+put          66 72 65 65 0D 62 61 73 69 63 0D
binary+get          66 72 65 65 0D 62 61 73 69 63 0D
binary+input()      66 72 65 65 0D 62 61 73 69 63 0D
input+get           66 72 65 65 0D 62 61 73 69 63 0D
input+input()       66 72 65 65 0D 62 61 73 69 63 0D

output+print        66 72 65 65 0D 62 61 73 69 63 0D
binary+get          66 72 65 65 0D 62 61 73 69 63 0D
binary+input()      66 72 65 65 0D 62 61 73 69 63 0D
input+get           66 72 65 65 0D 62 61 73 69 63 0D
input+input()       66 72 65 65 0D 62 61 73 69 63 0D
Linux wouldn't do the translation CR => CR+LF, so there would be difference there.
Post Reply