Qbasicnews.com

Full Version: LEN() oversight? Causes problems for GET()
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
This program is designed to demonstrate a failing of the FB library, or possibly of FB itself. However, if there is an elegant workaround for the problem highlighted, I'm intrested in that, too.


Code:
''This is a demo program to illustrate a failing in FB/QB

CLS
OPTION BASE 0    
''I'm not sure OPTION BASE really works. If I DIM something(12) as INTEGER, I don't get the values from 0 to 11, I seem to get values from 0 to 12, which amounts to 52 bytes, not the wanted 48 bytes (12 elements * 4bytes each)

TYPE pokey field = 1
  a(0 to 11) AS INTEGER        ''If I don't include a lower bound, is the number I specify the max index, or the actual number of elements requested as in C?
END TYPE

DIM toyInteger AS INTEGER
DIM toyString AS STRING * 12
REDIM torch(1 to 12) AS BYTE
REDIM dork(1 to 12) AS pokey

''Works, creates a basic table
FOR y = 1 TO 12
  FOR x = 0 TO 11
    dork(y).a(x) = x
  NEXT x
NEXT y

''Works, prints out the table
FOR y = 1 TO 12
  FOR x = 0 TO 11
    PRINT dork(y).a(x);
  NEXT x
  PRINT
NEXT y

PRINT
PRINT LEN(toyInteger)        ''Should print "4"
PRINT LEN(toyString)        ''Should print "12"
PRINT LEN(pokey)            ''Should print "48"
PRINT

''Here's the kicker: how do I get the length of the following arrays? It works for strings and single elements of arrays.
''It fails if I try to get the total length of an array.

PRINT "This element is"; LEN( dork(1).a(10) );" bytes long."    ''This should also print out "4"

''Now for the coup de gras
PRINT "This array is"; LEN( dork ); " bytes long."        ''This should print out "48", but it doesn't work, compiler doesn't like this.
PRINT "The torch array is"; LEN ( torch(1 to 12) ); " bytes long."    ''FBC doesn't like this either.

''This highlights a slight problem with the GET function, where you have to pass to it a pointer where you want the
''data copied to. Since LEN doesn't correctly get the length for an array, it makes it hard to fill an array of similar
''structures.  This is compounded by the fact that GET doesn't allow the user to specify the number of bytes to retrieve.
''This problem doesn't surface if you're using the standard datatypes singly, but it does appear when using arrays.


''Do some file opening stuff.
GET #1, , dork(1)        ''This gets in 48 bytes, the size of one element of dork.
GET #1, , dork            ''This fails because GET a) doesn't know how many bytes to get, and b) the compiler doesn't like the fact that the array is missing subscripts.

CLOSE #1

''However, this same general construct works in C, and probably other languages. Is there a way to get similar functionality?
That printed in version 0.11 (commenting that len( array(1 to 12) ) thing that is not allowed in qb/vb):

Code:
0 1 2 3 4 5 6 7 8 9 10 11
0 1 2 3 4 5 6 7 8 9 10 11
0 1 2 3 4 5 6 7 8 9 10 11
0 1 2 3 4 5 6 7 8 9 10 11
0 1 2 3 4 5 6 7 8 9 10 11
0 1 2 3 4 5 6 7 8 9 10 11
0 1 2 3 4 5 6 7 8 9 10 11
0 1 2 3 4 5 6 7 8 9 10 11
0 1 2 3 4 5 6 7 8 9 10 11
0 1 2 3 4 5 6 7 8 9 10 11
0 1 2 3 4 5 6 7 8 9 10 11
0 1 2 3 4 5 6 7 8 9 10 11

4
0
48

This element is 4 bytes long.
This array is 48 bytes long.

That's probably the 5th time i said LEN() was broken in version 0.10.

LEN() for fixed-len strings will actually return the string lenght, not the size, in QB you had to do : len( ltrim$( fixstring ) ), i find that stupid enough, as you already know how long is a fixed-len string as you have to explicitly declare them.. you can do:

Code:
const MAXSTRSIZE=1234: DIM fixstr as string * MAXSTRSIZE


And use that constant on any other parts of code if you want, GET # and PUT # and other rtlib routines when receiving fix-len strings will use the full size to access the string, not the current length.

To read/write the full array you must use () after the array name, as the array will be passed by descriptor to PUT # or GET #, that would be "GET #1, , dork()".

There's no ARRAYSIZE() or anything like that for arrays, you can get any array index using LBOUND and UBOUND, but you must know how many dimensions the array has.
Ok, I tried this.

I did manage to get a clean compilation.

However, there still seems to be a sort of a bug with GET, or maybe I'm just unlucky.

GET #1, , dork() Doesn't really seem to do anything. In fact, if I populate the entire dork structure, It appears to be overritten.

As a test of this, I set up a file 144 bytes in length, consisting of 0x00 thru 0x0b sequentially (the original grid), and ran GET on it.
I noticed a few funny things,

First, if I don't explicitly start the get at record 1, it starts getting at the last record that was PUT to. I think this is probably intentional.

Second, if I GET #1, 1, dork() 'Fill entire array of type dork
it seems to overwrite the entire array with zeroes.

If I try GETting just one element [ e.g. GET #1, 1, dork(1) ]
It gets one element of dork, except for one small problem, the initial byte of it seems to be made into a pointer or garbage number of some sort. This could have something to do with PRINT, but at least from what I can tell, it looks like garbage.


This is the .bas file, essentially a pared down working version of the former prog.
Code:
TYPE myType field = 1
  a(0 to 11) AS INTEGER
END TYPE

DIM dork(1 to 12) as myType

OPEN "test.dat" FOR BINARY AS #1

GET #1, 1, dork()

FOR y = 1 TO 12
  FOR x = 0 TO 11
    PRINT dork(y).a(x);
  NEXT x
  PRINT
NEXT y

The following is the actual data for test.dat
Code:
test.dat = {
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B},
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B},
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B},
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B},
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B},
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B},
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B},
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B},
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B},
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B},
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B},
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B}
}

Following is the output if I change the line GET #1, 1, dork() to GET #1, 1, dork(1)

Code:
50462976 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0

The original GET #1, 1, dork() only outputs zeroes.

Also, if I try to GET from a location that isn't in the file, it puts it in the file, such a situation occurs when trying to get from position 385 when the file is only 144 bytes long. This could be normal, though. I haven't done extensive GET and PUT from files in QB.
Worked fine for me, but i had to change the array field "a()" from INTEGER to BYTE, as the file is 144 bytes long -- INTEGER would try to read 4x more data.

Code:
TYPE myType field = 1
  a(0 to 11) AS byte
END TYPE

DIM foo(1 to 12) as myType

DIM bar(1 to 12) as myType


FOR y = 1 TO 12
  FOR x = 0 TO 11
    foo(y).a(x) = x
  NEXT x
NEXT y

OPEN "test.dat" FOR BINARY AS #1

PUT #1, 1, foo()

GET #1, 1, bar()

FOR y = 1 TO 12
  FOR x = 0 TO 11
    PRINT bar(y).a(x);
  NEXT x
  PRINT
NEXT y

close #1
I suppose this is one of those head-slapping "duh" moments for me. That should have been fairly obvious. I guess working on projects at midnght after being at work for 8 hours isn't always the most conducive to analytical troubleshooting.

Thanks Victor, I got it working like a charm as soon as I changed that.