Reading tabled data

BlitzMax Forums/BlitzMax Beginners Area/Reading tabled data

I've asked this question before, but at that time there wasn't a ready answer. Consequently, I had decided to wait until the full version was released with documentation. However, today after downloading the most recent update I noticed the stdc module, which includes fopen but not fscanf or fprintf. Anyway with some two months having passed, is there an easy way to read tabled data into a struct?

what exactly do you mean by tabled data?
perhaps you can give an example of the file you want to read?

Take the following as an example,

--

smith 34 160
jones 26 176
blake 29 166

---

In C,

#define MAXRECORDS 100

typedef struct
{
char name[30];
int age;
int height;
}DATA;

DATA *users = malloc(MAXRECORDS * sizeof(DATA));

then read the file so that individual records can be easily accessed using a numerical index. I use fscanf in this case and fprintf for the opposite. These functions have made it relatively easy to manage my data in C. As Blitzmax evolves I wouldn't mind migrating.

hmmm. I thought someone might have given you a good answer, as I think there might be a clever solution to this..
But from what I can gather, you should be able to do the same thing in 'Max relatively easy.. Say using banks or (RAM)streams...

[edit] DOH! Not what you asked :D

Something like this, might work:
Const MAXRECORDS = 100

Type Data
 Field name:String
 Field age:Int
 Field height:Int

 Method WhoIs()
  Print "Name: "+self.name+", Age: "+self.age+", Height: "+self.height+"cm"
 EndMethod
EndType

Local users:Data[MAXRECORDS]
For Local i = 0 Until MAXRECORDS
  users[i] = New Data
  users[i].name   = "Bob "+i
  users[i].age    = Rand(0,100)
  users[i].height = Rand(100,200)
Next

users[10].WhoIs()
users[45].WhoIs()
users[89].WhoIs()
You wouldn't need a max number of records, as you can easily resize the array if you need to.

Ok, I assume you will want to read the file, which has certain seperators to show, when a new entry is there?

So something like this should work:
Function ReadDString:String(stream:TStream,seperator:Byte[])
 If stream = Null
  Return ""
 EndIf
 Local b:byte
 Local s:String
 While Eof(stream) = False
  b = ReadByte(stream)
  For Local i = 0 Until seperator.length
   If b = seperator[i]
    Return s
   EndIf
  Next
  s :+ Chr(b)
 Wend
End Function
You then need to open a file, and supply that and a list of seperator values to it...
Something like this:
myfile = ReadFile("hello.txt")
Repeat
 Local s:string = ReadDString(myfile,[Asc(" "),10])
 Print s
Until s = ""
CloseFile(myfile)
It's not tested, so it might be buggy :)

Thank you for the examples.

I tend to use space separated variables and read until not EOF. I believe that fscanf is flexible in that the number of spaces dosn't matter. Hardcoding the separator would be less tolerant in this case.

I've created some code for you (with comments):
Type Data
	Global DataArray:Data[]

	Field Name$
	Field Age%
	Field Height%

	Function ReadTabledData(DFH%)
		Local LineFromFile$ = ReadLine$(DFH%) ' Read a line from the given filehandle

		Local a:Data = New Data ' Create a new "Data"-object

		' Store the name without ending spaces
		a.Name$ = LineFromFile$[..10] ' Copy the first 10 characters from the line into field Name$ (0..9)
		' Remove spaces at the end of the name
		While Chr(a.Name$[a.Name$.length - 1]) = Chr(32)
			a.Name$ = a.Name$[..(a.Name$.length - 1)]
		Wend

		a.Age% = Int(LineFromFile$[10..15]) ' Copy the characters 10..14 to the Age-field and convert to Int
		a.Height% = Int(lineFromFile$[15..20]) ' Copy characters 15..19 to the Height-field and convert to Int

		' Resize the array to hold one more object
		DataArray = DataArray[..(DataArray.length + 1)]
		' Add the new Data-object to the array
		DataArray[DataArray.length - 1] = a
	End Function
End Type




' Open a file for reading (DFH = DataFileHandle)
Local DFH% = ReadFile("c:\Test.txt")

' Keep reading until EndOfFile
While Not Eof(DFH%)
	Data.ReadTabledData(DFH%)
Wend

' Close the file
CloseFile(DFH%)



' Print all names and ages
For i = 0 Until Data.DataArray.length
	Print "Name = " + Chr(34) + Data.DataArray[i].Name$ + Chr(34)
	Print "    Age = " + Chr(34) + Data.DataArray[i].Age% + Chr(34)
	Print "    Height = " + Chr(34) + Data.DataArray[i].Height% + Chr(34)
	Print
Next

End


File Test.txt:
Johnny    20   185
Piet      27   170
Geert     26   182
Gert      28   120
Cornelis  50   150