views:

139

answers:

1

We have some ancient Delphi code (might have even originated as Turbo Pascal code) that uses {$I-}, aka {$IOCHECKS OFF}, which makes the code use IOResult instead of exceptions for disk I/O errors.

I want to get rid of the {$I-} and bring this code forward into the 1990s, but to do that, I'd like to know what all is affected by {$IOCHECKS OFF}. Does this only affect the crufty old built-in I/O functions like AssignFile / Reset / Rewrite / Append / CloseFile? Or does it affect more modern things like TFileStream as well? More importantly, what else might be affected that I'm not thinking of? (Delphi Basics suggests that it also affects MkDir and RmDir. If it affects those, there have to be more.)

The Delphi 2007 Help topic "Input output checking (Delphi)" (ms-help://borland.bds5/devcommon/compdirsinput_outputchecking_xml.html) says that this affects "I/O procedure[s]", and that "I/O procedures are described in the Delphi Language Guide." This doesn't help much, since CodeGear has never shipped a Language Guide, and the last time Borland shipped one was Delphi 5.

Which functions and classes behave differently under {$I-}?


EDIT: The accepted answer gives some great background, but here's the quick summary in alphabetized list form: {$IOCHECKS OFF} only affects the following routines from the System unit.

  • Append
  • BlockRead
  • BlockWrite
  • ChDir
  • CloseFile
  • Eof
  • Eoln
  • Erase
  • FilePos
  • FileSize
  • Flush
  • MkDir
  • Read
  • Readln
  • Rename
  • Reset
  • Rewrite
  • RmDir
  • Seek
  • SeekEof
  • SeekEoln
  • SetLineBreakStyle
  • Truncate
  • Write
  • Writeln
+4  A: 

Since $I is a compiler directive, it can only affect compiler-generated code, and it can only affect code that actually gets compiled.

For those two reasons, it cannot affect things like TFileStream. It's a class in Classes.pas, which is a unit you don't compile. Any code in it is not affected by the $I directive. Furthermore, the compiler doesn't treat that class specially in any way. It's just another ordinary class.

The $I directive affects the language built-in functions that you've mentioned. The compiler generates calls to those functions specially. It also affects calls to write, writeln, and readln. It should also affect BlockRead and BlockWrite.

You can check the source code. Anything that calls SetInOutRes is susceptible to $I. That includes functions that open files (Append, Reset, and Rewrite), as well as anything else that accepts a parameter of type file or TextFile (Flush, BlockRead, BlockWrite, Erase, FilePos, Seek, FileSize, Read, Readln, Write, Writeln, Rename, Eof, SeekEof, Eoln, SeekEol, Truncate, SetLineBreakStyle, and CloseFile). Also, anything that calls InOutError (ChDir, MkDir, amd RmDir).

Notably absent from the list is AssignFile. That function doesn't actually do any I/O. It just sets up the file record so that Append, Reset, and Rewrite will know what to do.


I should point out that looking at the source code is just inference. The $I directive controls whether the compiler will insert calls to the __IOTest function in your own code after you call certain other functions. That function checks the value of InOutRes, and if it's not zero, it raises a run-time error (which may yield an exception if SysUtils is included in your program). We can't check the source code to directly find out what functions are affected by $I (since it's only called in compiler-generated code), so we're really just looking for which functions set InOutRes, with the assumption that they wouldn't bother doing that if they didn't know the compiler would check for it afterward.

Rob Kennedy
Sweet - good to know how to track these down (and good grief, are there a lot of `_Read*` and `_Write*` methods in there!). It looks like you missed three, though: `SetLineBreakStyle`, `SeekEof`, and `SeekEoln`.
Joe White
Also of note is that this only affects routines in the System unit. Nothing else calls `SetInOutRes` or `InOutError`.
Joe White
All the `_Read*` and `_Write*` are there because `Read` and `Write` are compile magic. The compiler inserts a call to a specialized function for *each parameter* you pass to `Read` or `Write`. It inserts calls to `__IOTest` if `$I` is enabled.
Rob Kennedy
Not sure how I missed those functions. I remember seeing them. I've updated the answer to include them. Thanks.
Rob Kennedy