Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2004-02

blockread in a procedure

11 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

David Emerson

Hi there,

I'm having trouble using blockread. It was working for... oh, a year... and all of a sudden it's not working. I'm getting a runtime error 87 in win32/i386 (fpc 1.0.10) and an error 217 in linux/i386 (fpc 1.0.6). Since I always compile with -gl it tells me it's failing 's the code...

const
  test_file_name = 'test.txt';
  the_source : ansistring = '';
procedure read_source_file;
  const
    bufsize = 2048;
  var
    source_file : file;
    buf : array [1..bufsize] of char;
    count_read : longint;   // longint required by blockread
  begin
    write ('Reading source file.....');
    assign (source_file, test_file_name);
    reset (source_file);
    the_source := '';
    repeat
      blockread (source_file, buf, bufsize, count_read);
      the_source := the_source + copy (buf, 1, count_read);
      until count_read = 0;
    close (source_file);
    the_source := the_source + chr(255);
    writeln ('Source file successfully read');
  end;
begin
  read_source_file;
end.

If I get rid of the procedure read_source_file and put its code directly into the main "begin end." then it works. So for some reason, suddenly it can't stand having blockread inside a procedure. I haven't touched the procedure or any of the constants/variables associated with it in a long time, so it's bizarre that it suddenly decided to fail.

Incidentally, fpc 1.0.10 rpm failed to install on redhat. I struggled with it for a good hour. Any tips? Does the gz work better than the rpm?

Cheers,
David

Reply by email

Unknown author
to David Emerson
David Emerson wrote 43 lines
Hi there, I'm having trouble using blockread. It was working for... oh, a year... and all of a sudden it's not working. I'm getting a runtime error 87 in win32/i386 (fpc 1.0.10) and an error 217 in linux/i386 (fpc 1.0.6). Since I always compile with -gl it tells me it's failing 's the code... const test_file_name = 'test.txt'; the_source : ansistring = ''; procedure read_source_file; const bufsize = 2048; var source_file : file; buf : array [1..bufsize] of char; count_read : longint; // longint required by blockread begin write ('Reading source file.....'); assign (source_file, test_file_name); reset (source_file); the_source := ''; repeat blockread (source_file, buf, bufsize, count_read); the_source := the_source + copy (buf, 1, count_read); until count_read = 0; close (source_file); the_source := the_source + chr(255); writeln ('Source file successfully read'); end; begin read_source_file; end. If I get rid of the procedure read_source_file and put its code directly into the main "begin end." then it works. So for some reason, suddenly it can't stand having blockread inside a procedure. I haven't touched the procedure or any of the constants/variables associated with it in a long time, so it's bizarre that it suddenly decided to fail.

did you change the compiler, or one of the compiler flags ?

Incidentally, fpc 1.0.10 rpm failed to install on redhat. I struggled with it for a good hour. Any tips? Does the gz work better than the rpm?

What error do you get ? What version of rpm do you use ?

If the .rpm fails, the .gz should always install.

Michael.

Reply by email

Unknown author
to David Emerson: I'm having trouble using blockread. It was working for... oh, a year... and all of a…
David Emerson wrote
Hi there, I'm having trouble using blockread. It was working for... oh, a year... and all of a sudden it's not working. I'm getting a runtime error 87 in win32/i386 (fpc 1.0.10) and an error 217 in linux/i386 (fpc 1.0.6). Since I always compile with -gl it tells me it's failing 's the code...

I tested some things with the current compiler. The error occurs there as well. It's a stack problem. If you move the 'buf' definition out of the procedure, I.e. define it as a global var, it works fine.

Assuming you don't want to use a global variable (bad programming practice), you can also try the following, which works fine as well: (ansistrings are allocated on the heap, bypassing the stack);

Michael.

program testb;
const
  test_file_name = 'test.txt';
  the_source : ansistring = '';
const
  bufsize = 2048;
procedure read_source_file;
  var
    source_file : file;
    count_read : longint;   // longint required by blockread
    Buf : AnsiString;
  begin
    SetLength(Buf,BufSize);
    write ('Reading source file.....');
    assign (source_file, test_file_name);
    reset (source_file);
    the_source := '';
    repeat
      blockread (source_file, buf[1], bufsize, count_read);
      the_source := the_source + copy (buf, 1, count_read);
      until count_read = 0;
    close (source_file);
    the_source := the_source + chr(255);
    writeln ('Source file successfully read');
  end;
begin
  read_source_file;
end.

Reply by email

Unknown author
to David Emerson: I'm having trouble using blockread. It was working for... oh, a year... and all of a…
David Emerson wrote
Hi there, I'm having trouble using blockread. It was working for... oh, a year... and all of a sudden it's not working. I'm getting a runtime error 87 in win32/i386 (fpc 1.0.10) and an error 217 in linux/i386 (fpc 1.0.6). Since I always compile with -gl it tells me it's failing 's the code...

OK, last try. Not being entirely satisfied with my previous posts, I dug a little deeper. The strace on linux pointed me to the error.

Show quoted text 19 lines
const test_file_name = 'test.txt'; the_source : ansistring = ''; procedure read_source_file; const bufsize = 2048; var source_file : file; buf : array [1..bufsize] of char; count_read : longint; // longint required by blockread begin write ('Reading source file.....'); assign (source_file, test_file_name); reset (source_file);

This is the culprit. It should read

      reset (source_file,1);

By default, the blocksize is 128.

the_source := ''; repeat blockread (source_file, buf, bufsize, count_read);

With a blocksize of 128, this will try to read 128*2028 (256K) bytes. My guess is that the OS decides this is outside the valid stack range, and bails out. Chaning the blocksize to 1 in your original procedure makes things work just fine.

Remains the question how this ever could have worked.

Michael.

Reply by email

Marco van de Voort
to Unknown author: did you change the compiler, or one of the compiler flags ? What error do you get ? What…
Show quoted text 11 lines
On Sun, 29 Feb 2004, David Emerson wrote: > end. > > > If I get rid of the procedure read_source_file and put its code directly > into the main "begin end." then it works. So for some reason, suddenly > it can't stand having blockread inside a procedure. I haven't touched > the procedure or any of the constants/variables associated with it in a > long time, so it's bizarre that it suddenly decided to fail. did you change the compiler, or one of the compiler flags ?

It could be the copy(array of char). It was bugged in 1.9.x too, and got fixed somewhere in august-september (it was pretty much the bug that prevented the compiled twsocket from working).

IOW, try 1.9.2

Reply by email

David Emerson
to Unknown author: did you change the compiler, or one of the compiler flags ? What error do you get ? What…

Thanks for your help with blockread. Giving the blocksize with reset (myfile, 1) fixed it!

> Incidentally, fpc 1.0.10 rpm failed to install on redhat. I struggled with it for a good hour. Any tips? Does the gz work better than the rpm? What error do you get ? What version of rpm do you use ?

Installation worked fine with the tar + script, so I'm set for now. Re: rpm error... The installer prompted me for a root password, and then brought up a little box that said "calculating package dependencies". Then the box disappeared, without any error message or indication of status. Inspection revealed that it had not installed anything. Now that I think about it, I realize I couldn't have spent nearly an hour on it.

I don't really know what version of rpm I use... if you're really curious, and can tell me where to look for the version info, I'll get it for you. I'm really an amateur with linux. The best answer I can give you right now is: "whatever comes with the RedHat 8.0 that the computer manufacturer pre-installed for me" :-)

Thanks!
-David

Reply by email

Michael Van Canneyt
to David Emerson
David Emerson wrote 9 lines
Thanks for your help with blockread. Giving the blocksize with reset (myfile, 1) fixed it! >> Incidentally, fpc 1.0.10 rpm failed to install on redhat. I struggled with it for a good hour. Any tips? Does the gz work better than the rpm? > >What error do you get ? What version of rpm do you use ? Installation worked fine with the tar + script, so I'm set for now. Re: rpm error... The installer prompted me for a root password, and then brought up a little box that said "calculating package dependencies". Then the box disappeared, without any error message or indication of status. Inspection revealed that it had not installed anything. Now that I think about it, I realize I couldn't have spent nearly an hour on it. I don't really know what version of rpm I use... if you're really curious, and can tell me where to look for the version info, I'll get it for you. I'm really an amateur with linux. The best answer I can give you right now is: "whatever comes with the RedHat 8.0 that the computer manufacturer pre-installed for me" :-)

Open a shell window and type 'rpm --version', this should give something like:

obelix ~# rpm --version
RPM version 3.0.6

It's possible that the version with which the distribution was built is newer than the version installed on your system, that could lead to errors....

Michael.

Reply by email

David Emerson
to Unknown author: did you change the compiler, or one of the compiler flags ? What error do you get ? What…

Hey all,

I've been poking around the sources and documentation for some insight into the details of how ansistrings are implemented, and I am left with some questions.

It would be nice if, when comparing two ansistrings, fpc would first check to see if these two pointers are pointing to the same spot in memory, i.e. the same TAnsiRec. If they happen to be pointing to the same, a potentially long operation is reduced to a simple comparison of two memory addresses which probably only takes one processor cycle.

Looking at fpc_ansistr_compare in astrings.inc, (the only function that seems to call fpc_ansistr_compare), it appears not to do this. Perhaps I'm wrong? I don't _really_ understand what the code is doing. I believe the sources I'm looking at are 1.0.10.

If this quick comparison is in fact not implemented, I'd like to do it myself. (There are a number of places where I am checking long ansistrings for equality, and there is a reasonable chance that both pointers are pointing to the same address.)

( @s1[1] = @s2[1] ) seems to give the right result. is this the best way? or is it quicker/slower to use ( pointer(s1) = pointer(s2) ) (no doubt more elegant)

Now on to the second question... getting those ansistrings pointed to the same address! (Some of them already are, but I'd like to get more...)

I was kind of surprised to find that

  s1 := 'hello';
  s2 := 'hello';
  writeln ( pointer(s1) = pointer(s2) );     ...writes FALSE

Thus I assume that

  readln (s1);
  readln (s2);    ... would NEVER point them at the same address

Of course, checking every string against every other string would comprise an absurd performance hit in most cases. What I'd really like is to have a relatively small number of constant strings that could be compared against, and only when reading in a data file, or perhaps certain fields in a data file. (yeah, reading will take longer)... Then if my data file (and thus my filled pascal array) has 1,000 instances of "some_complex_but_often_identically_repeated_data_value", I get the following:
- lots of memory savings
- operator "=" gives a very fast TRUE result when they are pointing to the same

In fact, all the string comparison operators return a particular value if the two are equal, so they could all give a fast result in this case. This could happen both when comparing datum values against each other, and when comparing them to a constant string in my code.

Do resource strings offer this kind of intelligence, or are they designed for a completely different purpose, and offer no performance improvement for this special application?

Is there some special mode or compiler directive that does more string uniqueness checking, including at compile time (e.g. to find my two identical 'hello' assignments)?

Or shall I bite the bullet and decide whether I need to implement some of this stuff myself?

(( Typcasting my data into something that's not literal strings would of course be the best thing to do. However, I'm not quite ready for it yet, and would like to do what I can to help performance until I get to the point where I can put my data in pascal records. ))

Cheers!
-David

Reply by email

David Emerson
to Michael Van Canneyt: Open a shell window and type 'rpm --version', this should give something like: obelix ~#…

For the record: RPM version 4.1

Re: rpm error... The installer prompted me for a root password, and then brought up a little box that said "calculating package dependencies". Then the box disappeared, without any error message or indication of status. Inspection revealed that it had not installed anything. Now that I think about it, I realize I couldn't have spent nearly an hour on it.

-David

Reply by email

Michael Van Canneyt
to David Emerson: I've been poking around the sources and documentation for some insight into the details…
David Emerson wrote 8 lines
Hey all, I've been poking around the sources and documentation for some insight into the details of how ansistrings are implemented, and I am left with some questions. It would be nice if, when comparing two ansistrings, fpc would first check to see if these two pointers are pointing to the same spot in memory, i.e. the same TAnsiRec. If they happen to be pointing to the same, a potentially long operation is reduced to a simple comparison of two memory addresses which probably only takes one processor cycle. Looking at fpc_ansistr_compare in astrings.inc, (the only function that seems to call fpc_ansistr_compare), it appears not to do this. Perhaps I'm wrong? I don't _really_ understand what the code is doing. I believe the sources I'm looking at are 1.0.10.

This is already implemented in version 1.9.2.

Show quoted text 6 lines
If this quick comparison is in fact not implemented, I'd like to do it myself. (There are a number of places where I am checking long ansistrings for equality, and there is a reasonable chance that both pointers are pointing to the same address.) ( @s1[1] = @s2[1] ) seems to give the right result. is this the best way? or is it quicker/slower to use ( pointer(s1) = pointer(s2) ) (no doubt more elegant)

The code uses ( pointer(s1) = pointer(s2) )

Show quoted text 11 lines
Now on to the second question... getting those ansistrings pointed to the same address! (Some of them already are, but I'd like to get more...) I was kind of surprised to find that s1 := 'hello'; s2 := 'hello'; writeln ( pointer(s1) = pointer(s2) ); ...writes FALSE

This is normal. But if you do it 'correct', i.e:

Const
  MyHello = 'Hello';
S1:= MyHello;
S2:= MyHello;

They will point at the same address.

Show quoted text 12 lines
Thus I assume that readln (s1); readln (s2); ... would NEVER point them at the same address Of course, checking every string against every other string would comprise an absurd performance hit in most cases. What I'd really like is to have a relatively small number of constant strings that could be compared against, and only when reading in a data file, or perhaps certain fields in a data file. (yeah, reading will take longer)... Then if my data file (and thus my filled pascal array) has 1,000 instances of "some_complex_but_often_identically_repeated_data_value", I get the following: - lots of memory savings - operator "=" gives a very fast TRUE result when they are pointing to the same In fact, all the string comparison operators return a particular value if the two are equal, so they could all give a fast result in this case. This could happen both when comparing datum values against each other, and when comparing them to a constant string in my code. Do resource strings offer this kind of intelligence, or are they designed for a completely different purpose, and offer no performance improvement for this special application?

They are normal ansistrings, just stored in a special table.

Is there some special mode or compiler directive that does more string uniqueness checking, including at compile time (e.g. to find my two identical 'hello' assignments)?

No. Please use constants, that's what they're for.

Michael.

Reply by email

Peter Vreman
to Michael Van Canneyt
Show quoted text 5 lines
> I was kind of surprised to find that > > s1 := 'hello'; > s2 := 'hello'; > writeln ( pointer(s1) = pointer(s2) ); ...writes FALSE

Above returns TRUE when compiled with 1.9.x.

Note: It is not garaunteed to work always. Like when s1 is assigned in unit A and s2 is assigned in unit B.

Reply by email