unit StreamFile; { Copyright 1996, 1997 Colosseum Builders, Inc This software is provided as is. We have not tested this code with your software. Unix Stream File Interface Author: John M. Miano miano@colosseumbuilders.com The purpose of this unit is to address the problem of writing to text files on networked drives on Unix systems. In Unix each record in a text file is separated by a characters. In MS-DOG and Windoze records are separated by a pair. This unit allows you to read and write files in the Unix format. To use this unit, simply call AssignStreamFile instead of Assign to open the file. From then on use the standard Pascal I/O functions. File : TextFile ; ... AssignStreamFile (File, 'MYFILE.TXT') ; ... Now treat the file use like any other. } interface Uses SysUtils ; Procedure AssignStreamFile (var F : Text ; Filename : String) ; implementation Const BufferSize = 128 ; Type TStreamBuffer = Array [1..High (Integer)] of Char ; TStreamBufferPointer = ^TStreamBuffer ; TStreamFileRecord = Record Case Integer Of 1: ( Filehandle : Integer ; Buffer : TStreamBufferPointer ; BufferOffset : Integer ; ReadCount : Integer ; ) ; 2: ( Dummy : Array [1 .. 32] Of Char ) End ; Function StreamFileOpen (var F : TTextRec) : Integer ; Var Status : Integer ; Begin With TStreamFileRecord (F.UserData) Do Begin GetMem (Buffer, BufferSize) ; Case F.Mode Of fmInput: FileHandle := FileOpen (StrPas (F.Name), fmShareDenyNone) ; fmOutput: FileHandle := FileCreate (StrPas (F.Name)) ; fmInOut: Begin FileHandle := FileOpen (StrPas (F.Name), fmShareDenyNone Or fmOpenWrite or fmOpenRead) ; If FileHandle <> -1 Then status := FileSeek (FileHandle, 0, 2) ; { Move to end of file. } F.Mode := fmOutput ; End ; End ; BufferOffset := 0 ; ReadCount := 0 ; F.BufEnd := 0 ; { If this is not here it thinks we are at eof. } If FileHandle = -1 Then Result := -1 Else Result := 0 ; End ; End ; Function StreamFileInOut (var F : TTextRec) : Integer ; Procedure Read (var Data : TStreamFileRecord) ; Procedure CopyData ; Begin While (F.BufEnd < Sizeof (F.Buffer) - 2) And (Data.BufferOffset <= Data.ReadCount) And (Data.Buffer [Data.BufferOffset] <> #10) Do Begin F.Buffer [F.BufEnd] := Data.Buffer^ [Data.BufferOffset] ; Inc (Data.BufferOffset) ; Inc (F.BufEnd) ; End ; If Data.Buffer [Data.BufferOffset] = #10 Then Begin F.Buffer [F.BufEnd] := #13 ; Inc (F.BufEnd) ; F.Buffer [F.BufEnd] := #10 ; Inc (F.BufEnd) ; Inc (Data.BufferOffset) ; End ; End ; Begin F.BufEnd := 0 ; F.BufPos := 0 ; F.Buffer := '' ; Repeat Begin If (Data.ReadCount = 0) Or (Data.BufferOffset > Data.ReadCount) Then Begin Data.BufferOffset := 1 ; Data.ReadCount := FileRead (Data.FileHandle, Data.Buffer^, BufferSize) ; End ; CopyData ; End Until (Data.ReadCount = 0) Or (F.BufEnd >= Sizeof (F.Buffer) - 2) ; Result := 0 ; End ; Procedure Write (var Data : TStreamFileRecord) ; Var Status : Integer ; Destination : Integer ; II : Integer ; Begin With TStreamFileRecord (F.UserData) Do Begin Destination := 0 ; For II := 0 To F.BufPos - 1 Do Begin If F.Buffer [II] <> #13 Then Begin Inc (Destination) ; Buffer^[Destination] := F.Buffer [II] ; End ; End ; Status := FileWrite (FileHandle, Buffer^, Destination) ; F.BufPos := 0 ; Result := 0 ; End ; End ; Begin Case F.Mode Of fmInput: Read (TStreamFileRecord (F.UserData)) ; fmOutput: Write (TStreamFileRecord (F.UserData)) ; End ; End ; Function StreamFileFlush (var F : TTextRec) : Integer ; Begin Result := 0 ; End ; Function StreamFileClose (var F : TTextRec) : Integer ; Begin With TStreamFileRecord (F.UserData) Do Begin FreeMem (Buffer) ; FileClose (FileHandle) ; End ; Result := 0 ; End ; Procedure AssignStreamFile (var F : Text ; Filename : String) ; Begin With TTextRec (F) Do Begin Mode := fmClosed ; BufPtr := @Buffer ; BufSize := Sizeof (Buffer) ; OpenFunc := @StreamFileOpen ; InOutFunc := @StreamFileInOut ; FlushFunc := @StreamFileFlush ; CloseFunc := @StreamFileClose ; StrPLCopy (Name, FileName, Sizeof(Name) - 1) ; End ; End ; end.