yeputons
yeputons

Reputation: 9238

Why does Delphi 7 truncate file after ASCII code 14 when opening in Append mode?

I'm working on some legacy software written in Delphi 7 which runs on Windows. I've minified the problem to the following program:

var f: text;
begin
  assign(f, 'a.txt');
  rewrite(f);
  writeln(f, 'before' + chr(14) + 'after');
  close(f);

  assign(f, 'a.txt');
  append(f);
  close(f);
end.

I expect it to create a.txt file containing "before#14after#13#10" and then append nothing to it. However, after I run this program on Windows, I see before in a.txt instead, like if Delphi's append truncates the file. If I do not re-open the file, it shows before#14after#13#10 as expected.

If I write something (FooBar) in the re-opened file, it's appended, but as if the file was already truncated: beforeFooBar.

This effect does not occur with any other character between 0 and 32, even with 26 (which stands for EOF).

Is this a bug in Delphi or a well-defined behavior? What is so special about chr(14)?

Upvotes: 6

Views: 241

Answers (1)

yeputons
yeputons

Reputation: 9238

Thanks to some friends from a chat and Sertac Akyuz from comments: it looks like a bug in Delphi 7.

It's supposed to have special handling of the EOF symbol (ASCII 26), quoting from here:

Note: If a Ctrl+Z (ASCII 26) is present in the last 128-byte block of the file, the current file position is set so that the next character added to the file overwrites the first Ctrl+Z in the block. In this way, text can be appended to a file that terminates with a Ctrl+Z.

Kind of CP/M backward compatibility, I guess.

However, there is a bug in the implementation of TextOpen for Windows (see Source/Rtl/Sys/System.pas from your Delphi 7 installation around line 4282):

@@loop:
        CMP     EAX,EDX
        JAE     @@success

//    if  (f.Buffer[i] == eof)

        CMP     byte ptr [ESI].TTextRec.Buffer[EAX],eof
        JE      @@truncate
        INC     EAX
        JMP     @@loop

Here it says eof instead of cEof. Unfortunatley, that compiles for some reason and it even appeared on StackOverflow already. There is a label called @@eof and that's pretty much it.

Consequence: instead of having special case for 26, we have special case for 14. The exact reason is yet to be found.

Upvotes: 5

Related Questions