Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 09:59 03 Aug 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Quirk in the INPUT #n command.

Author Message
Paul_L
Guru

Joined: 03/03/2016
Location: United States
Posts: 769
Posted: 09:57pm 15 Jul 2018
Copy link to clipboard 
Print this post

This is interesting. INPUT #n won't read a comma separated list of values in separate statements in a loop from a file. The following code, run under DOS, will generate two data files "TEST1.DAT" and "TEST2.DAT". It will read the values in the second file, but not in the first. How do you make an INPUT # command in a loop read a comma separated list?

Paul in NY


Option base 1
Dim T%(10)

For i%=1 To 10:T%(i%)=i%:Next
For i%=1 To 10:Print T%(i%),:Next:Print '>>>> "1 2 3 4 5 6 7 8 9 10"
Open "test1.dat" For output As #1
For i%=1 To 10
Print #1, Str$(T%(i%)); '<<<<<<<<<<<< writes "1,2,3,4,5,6,7,8,9,10" to file
If i%<10 Then Print #1,",";
Next
Close #1
Open "test1.dat" For input As #1
For i%=1 To 10
Input #1, T%(i%) '>>>>>>>>>>>>>>>>>>>>>>>>>>>> reads "1,0,0,0,0,0,0,0,0,0"
Next
Close #1
For i%=1 To 10:Print T%(i%),:Next:Print '>>>>> "1 0 0 0 0 0 0 0 0 0"

Print
For i%=1 To 10:T%(i%)=i%:Next
For i%=1 To 10:Print T%(i%),:Next:Print '>>>> "1 2 3 4 5 6 7 8 9 10"
Open "test2.dat" For output As #1
For i%=1 To 10
Print #1, Str$(T%(i%))
Next '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ;>>> writes one value to each of ten lines
Close #1
Open "test2.dat" For input As #1
For i%=1 To 10
Input #1, T%(i%) '>>>>>>>>>>>>>>>>>>>>>>>>>>> reads "1,2,3,4,5,6,7,8,9,10"
Next
Close #1
For i%=1 To 10:Print T%(i%),:Next:Print '>>>> "1 2 3 4 5 6 7 8 9 10"
 
Justplayin

Guru

Joined: 31/01/2014
Location: United States
Posts: 328
Posted: 11:38pm 15 Jul 2018
Copy link to clipboard 
Print this post

To read a line of data at a time use LINE INPUT #n instead.

--CurtisEdited by Justplayin 2018-07-17
I am not a Mad Scientist...  It makes me happy inventing new ways to take over the world!!
 
flip
Senior Member

Joined: 18/07/2016
Location: Australia
Posts: 114
Posted: 11:43pm 15 Jul 2018
Copy link to clipboard 
Print this post

Agreed I have noticed this too, and worked around with routines for the purposes

To further amplify the point, the following works
Open "test1.dat" For input As #1
Input #1, T%(1), T%(2), T%(3), T%(4), T%(5), T%(6), T%(7), T%(8), T%(9), T%(10)
Close #1
For i%=1 To 10:Print T%(i%),:Next:Print '>>>>> "1 2 3 4 5 6 7 8 9 10"


It's as if the Input command reads a line...interesting to see what happens if the CSV line is >255 (not tested running out of time)

Of course I'm sure you worked out there are some ways to workaround this.

LINE INPUT #hF,buf$ (if you know the limes are always 255 chars or less)
buf$=INPUT$(n,#hF)

Both are a little tricky as you need to manage EOF but you can hide the untidiness in a routine.

Regards Phil
 
Paul_L
Guru

Joined: 03/03/2016
Location: United States
Posts: 769
Posted: 01:40am 16 Jul 2018
Copy link to clipboard 
Print this post

I guess there's no way to read sequential comma delimited variables from one line using a loop to cycle through array positions. The INPUT # command insists on moving its pointer to the next line when it terminates.

I wonder if Geoff could figure out a way to modify this behavior. Right now when INPUT encounters a comma in the data source line it continues along the source line to read the next variable as long as there are remaining variables in the {INPUT #n,V1,V2,V3,...,Vn} line. It moves the data pointer to the next line at the end of the INPUT line.

If the command line terminated with a comma {INPUT #n,V1,V2,V3,} would it be possible to not move the data pointer?

Then this code { for i=1 to 10:input #1,T%(i),:next } would read a data line like {DATA 1,2,3,4,5,6,7,8,9,10} with no trouble.

Paul in NY
Edited by Paul_L 2018-07-17
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 03:25am 16 Jul 2018
Copy link to clipboard 
Print this post

If you know how many values on each line, read that many at a time.

If you don't know how many, look at the function written by Geoff to split up the fields of a GPS stream.
It can be easily used to do what you are trying to achieve (if I read the problem correctly).

Jim

VK7JH
MMedit
 
Paul_L
Guru

Joined: 03/03/2016
Location: United States
Posts: 769
Posted: 07:33am 16 Jul 2018
Copy link to clipboard 
Print this post

Hi Jim,

The file contains 167 integers which are the calibration variables for my geothermal program. Most of them are contained in arrays within the program. I was planning on writing them out in rows and columns to simulate the arrays so that hand editing of the data file would be convenient. Using LINE INPUT #n to read the lines and then splitting the line at the commas seems inconvenient because the lines would not all be the same length.

I decided to write the file with one variable per line followed by a comma and text to identify the variable. This will enable hand editing of the file if it is needed, and it will also simplify reading the file with simple INPUT #n commands in loops. I've written the needed code and tested it and it seems usable.

Paul in NY
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2442
Posted: 10:37am 16 Jul 2018
Copy link to clipboard 
Print this post

the use of INPUT #n,V1,V2,...,Vn, (with a trailing comma) seems logical, as it would match the way the PRINT statement works. this could be a worthwhile addition geoff may like to think about adding to the language.

another thing i have been thinking about over the last few days is the usefulness of having a constant called "NaN".

NaN is a floating point constant, the name standing for 'not a number'. it is an invalid bit pattern that can NOT be obtained as a result of any calculation, and as such can be quite useful in detecting if a floating-point variable has had nothing assigned to it.

for instance:

Do
A=NaN
Input "enter a number ", A
If A=NaN Then
Print "no number entered"
Else
Print "you entered ";A
EndIf
Loop


without the line A=NaN the interpreter's behaviour could easily be made the same as for standard basic (where just pressing enter results in A being assinged the value 0.0).

unfortunately, integer variables do not have invalid bit patterns available, so there is no integer equivalent to NaN.


cheers,
rob :-)
 
flip
Senior Member

Joined: 18/07/2016
Location: Australia
Posts: 114
Posted: 01:11pm 16 Jul 2018
Copy link to clipboard 
Print this post

Hi Paul,
I had some time to test more and, as we both guessed it is a line read per INPUT # statement.

There is no way you can use INPUT# or LINE INPUT# to read 167 integers because internally both statements are limited to lines of 255 characters.

I now recall Geoff mentioning this limitation before...demonstrated as follows

open "Test3.dat" for output as 1
Print #1, Str$(1/7)","Str$(1/9)","Str$(1/11)","Str$(1/12)","Str$(1/13)","Str$(1/14)",";
Print #1, Str$(1/7)","Str$(1/9)","Str$(1/11)","Str$(1/12)","Str$(1/13)","Str$(1/14)",";
Print #1, Str$(1/7)","Str$(1/9)","Str$(1/11)","Str$(1/12)","Str$(1/13)","Str$(1/14)",";
Print #1, Str$(1/7)
close #1
'This file is a single line of 260 bytes
' EVEN reading ONE variable will fail the program
Open "test3.dat" For input As #1
Input #1,T%(1)
'[47] Input #1,T%(1)
'Error: Line is too long
Close #1


Geoff's answer (if I recall correctly) is that the intent is that the INPUT statement was only intended to read/save a few values, not intended to support a full blown DB, therefore he wasn't planning to address it.

That said, other methods may work more efficiently. The methods depend on whether speed or minimum storage is the more critical requirement. I've used both..following is what I use for minimal number of bytes (depending on integer value range required)

Function IntToChr(iVal As INTEGER,nChrs As INTEGER) As STRING
' Converts an unsigned INTEGER TO a character STRING of length nChrs
' little-endian
' nChrs must be between 1 and 8 (no bounds checking because this is an internal function)
Local As INTEGER iTmp=iVal
Local As INTEGER iRmndr
Local i As INTEGER
For i=1 To nChrs
iRmndr = iTmp Mod 256
iTmp = iTmp \ 256
IntToChr = Chr$(iRmndr) + IntToChr
Next i
End Function
Function ChrToInt(sVal As STRING) As INTEGER
' Inverse FUNCTION of IntToChr (little-endian)
Local i As INTEGER
For i=1 To Len(sVal)
ChrToInt = 256*ChrToInt + Asc(Mid$(sVal,i,1))
Next i
End Function

Option Base 1

ElementByteSize%=3
rows%=30
cols%=267
Dim a%(rows%,cols%)

'Load up array values for later checking and write to file
Open "test4.dat" For Output As #4
For i%=1 To rows%
For j%=1 to cols%
a%(i%,j%)=i%*10000+j%
Print #4,IntToChr(a%(i%,j%), ElementByteSize%);
Next j%
Next i%
Close #4

Open "test4.dat" For Input As #4
For i%=1 To rows%
For j%=1 to cols%
elem%=ChrToInt(Input$(ElementByteSize%,#4))
If (i%=1 and j%=1) or (i%=rows% and j%=cols%) then Print "element"i%","j% " when read back is" elem% ", should be same as written:"a%(i%,j%)
If elem%<>a%(i%,j%) Then Print "FAIL!!! element"i%","j% " when read back is" elem% ", should be same as written:"a%(i%,j%)
Next j%
Next i%
Close #4


Regards,
Phil
 
Paul_L
Guru

Joined: 03/03/2016
Location: United States
Posts: 769
Posted: 10:56pm 16 Jul 2018
Copy link to clipboard 
Print this post

  robert.rozee said   the use of INPUT #n,V1,V2,...,Vn, (with a trailing comma) seems logical, as it would match the way the PRINT statement works. this could be a worthwhile addition geoff may like to think about adding to the language.

That's what I thought. The INPUT command must read the entire line of code at one time. It then has to scan the code line for delimiters (",") to decide if it has to accept multiple variables. Assuming it finds multiple variables it would probably then read the data line until it finds a delimiter (",") then evaluate the line thus far while leaving the pointer paused. The process would then repeat until either the variables in the code line are exhausted or until the data line ends.

What I'm doing now, writing each variable to its own line followed by human readable identification, which enables manual editing of the data file, like this, 999, S%(1,1), and then reading it in a loop with the command, INPUT S%(i%,j%)", seems to work, but I'm not sure why.

When INPUT is expecting a numeric value I think it uses VAL() to find the 999 and then ignores the rest of the line after the first non-numeric character , S%(1,1)}.

Can you clarify the operation of the INPUT command? Does it read the data line until it finds a non-numeric character then quit? Exactly what characters are guaranteed to cause it to quit reading? For example, would a "|" or "," or ">" always work?

These are a few lines from the 173 line calibration data file which I am using currently.


35, S%(1,1)
120, S%(1,2)
35, S%(1,3)
125, S%(1,4)
5, S%(1,5)
35, S%(2,1)
120, S%(2,2)
35, S%(2,3)


Paul in NY
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025