Advertisement
LarsFosdal

UnixText.pas - Text File Device Driver example

Dec 22nd, 2017
596
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 6.63 KB | None | 0 0
  1. unit UnixText;
  2. { UNIXTEXT.PAS - Transparent reads/writes on a Unix text file
  3.  
  4.   Written by Lars Fosdal ([email protected]), March 23, 1994
  5.   Released to the public domain, March 23, 1994
  6.  
  7.   Written in Borland Pascal 7.01
  8.  
  9.   Allows using Readln/Writeln directly on a Unix text file by
  10.   translating LF to CRLF on Reads, and stripping CR's on Writes.
  11.  
  12.   Limitation:
  13.   All CR's will be stripped on Writes.  To strip only from CRLF
  14.   combinations, a redesign of the PC2Unix function which
  15.   implements lookahead is required.
  16.   I found this unnecessary for most purposes.
  17. }
  18.  
  19. interface
  20.  
  21. const
  22.   UnixFlushTreshold = 512; { Flush if less that xxx bytes free in buffer }
  23.   MaxUnixBufferSize = 16384; { Max buffer size }
  24.   { Remember that two buffers will be allocated }
  25.  
  26. procedure AssignUnix(var F: Text; name: string; BufferSize: Word);
  27.  
  28. implementation
  29.  
  30. type
  31.   pFile = ^ file; { Pointer to a binary file }
  32.  
  33.   { TTextRec contains a UserData field with 16 bytes, which is
  34.     documented not to be used by the Borland file system. }
  35.  
  36.   pUnixRec = ^RUnixRec; { TTextRec.UserData type cast }
  37.  
  38.   RUnixRec = record
  39.     DataFile: pFile; { Pointer to the "text" file }
  40.     ReadBuf: Pointer;
  41.     Unused: array [9 .. 16] of Byte; { not used }
  42.   end; { REC RUnixRec }
  43.  
  44. function Unix2PC(var iBuf; var oBuf; iCount: Word): Word; far;
  45. { - Translate LF to CRLF - Return new char count }
  46. begin
  47.   ASM
  48.     push ds           { Remember current dataseg }
  49.     mov  cx, iCount   { How many chars to translate? }
  50.     mov  dx, di
  51.     jcxz @@Done       { Quit if none }
  52.     mov  bx, 0A0Dh    { Store CRLF in BX (reversed) }
  53.     les  di, oBuf     { ES:DI -> oBuf }
  54.     lds  si, iBuf     { DS:SI -> iBuf }
  55.     mov  dx, di
  56.     cld
  57.   @@Nxt:
  58.     lodsb           { get a char }
  59.     cmp al, 0Ah     { was it a LF? }
  60.     je @@LF
  61.     stosb           { nope, store it }
  62.     loop @@Nxt      { are there any more chars? }
  63.     jmp @@Done
  64.   @@LF: mov ax, bx      { it was a LF, get the CRLF }
  65.     stosw           { and store it }
  66.     loop @@Nxt      { are there any more chars? }
  67.   @@Done:
  68.     pop  ds           { restore ds }
  69.     mov  ax, di       { determine number of chars stored }
  70.     sub  ax, dx
  71.     mov @Result, ax
  72.   END;
  73. end; { FUNC Unix2PC }
  74.  
  75. function UnixRead(var F: TTextRec): Integer; far;
  76. { - Called by Read, ReadLn, Eof, Eoln, SeekEof, SeekEoln }
  77. var
  78.   Unix: pUnixRec;
  79.   BytesIn: Integer;
  80. begin
  81.   Unix := @F.UserData;
  82.   BlockRead(Unix^.DataFile^, Unix^.ReadBuf^, F.BufSize shr 1, BytesIn);
  83.   F.BufEnd := Unix2PC(Unix^.ReadBuf^, F.BufPtr^, BytesIn);
  84.   F.BufPos := 0;
  85.   UnixRead := IOResult; { Return BlockRead IO result }
  86. end; { FUNC UnixRead }
  87.  
  88. function PC2Unix(var iBuf, oBuf; iCount: Word): Word; far;
  89. { - Strip carriage returns }
  90. begin
  91.   ASM
  92.     push ds           { remember ds }
  93.     mov dx, di
  94.     mov cx, iCount    { how many chars? }
  95.     jcxz @@Done
  96.     lds si, iBuf      { DS:SI -> iBuf }
  97.     les di, oBuf      { ES:DI -> oBuf }
  98.     mov dx, di
  99.     cld
  100.   @@Nxt:
  101.     lodsb           { get next char }
  102.     cmp al, 0Dh     { if it is a CR... }
  103.     je @@Skip       { ignore it }
  104.     stosb           { if not, store it }
  105.   @@Skip:
  106.     loop @@Nxt      { are there any more chars }
  107.   @@Done:
  108.     pop ds            { restore ds }
  109.     mov ax, di        { determine number of chars stored }
  110.     sub ax, dx
  111.     mov @Result, ax
  112.   END;
  113. end; { FUNC PC2Unix }
  114.  
  115. function UnixWrite(var F: TTextRec): Integer; far;
  116. { - Called by Write, Writeln, Close, and also by fmOutput mode flush }
  117. var
  118.   Unix: pUnixRec;
  119.   BytesOut: Integer;
  120. begin
  121.   Unix := @F.UserData;
  122.   BytesOut := PC2Unix(F.BufPtr^, Unix^.ReadBuf^, F.BufPos);
  123.   BlockWrite(Unix^.DataFile^, Unix^.ReadBuf^, BytesOut);
  124.   F.BufPos := 0;
  125.   UnixWrite := IOResult; { Return BlockWrite IO result }
  126. end; { FUNC UnixWrite }
  127.  
  128. function UnixWriteFlush(var F: TTextRec): Integer; far;
  129. { - Flush buffer to disk - a buffer size treshold have been added to
  130.   improve performance by avoiding a write after every write/writeln }
  131. begin
  132.   if ((F.BufSize shr 1) - F.BufPos) < UnixFlushTreshold then
  133.     UnixWriteFlush := UnixWrite(F) { Write flush }
  134.   else
  135.     UnixWriteFlush := 0;
  136. end; { FUNC UnixWriteFlush }
  137.  
  138. function UnixOpen(var F: TTextRec): Integer; far;
  139. { - Called by Reset, Append, or Rewrite }
  140. var
  141.   Unix: pUnixRec;
  142. begin
  143.   Unix := @F.UserData;
  144.   if not Assigned(F.BufPtr)
  145.    then GetMem(F.BufPtr, F.BufSize); { Allocate buffers }
  146.  
  147.   if not Assigned(Unix^.ReadBuf)
  148.    then GetMem(Unix^.ReadBuf, F.BufSize);
  149.  
  150.   if not Assigned(Unix^.DataFile)
  151.    then New(Unix^.DataFile); { Make space for the device driver file }
  152.  
  153.   Assign(Unix^.DataFile^, F.Name); { and assign the file name to it }
  154.   case F.Mode of { The ,1 indicates a 1 byte block size }
  155.     fmInput:
  156.       begin
  157.         Reset(Unix^.DataFile^, 1);
  158.         F.InOutFunc := @UnixRead;
  159.         F.FlushFunc := nil;
  160.       end;
  161.     fmInOut:
  162.       begin { fmInOut is passed by Append }
  163.         Reset(Unix^.DataFile^, 1);
  164.         Seek(Unix^.DataFile^, FileSize(Unix^.DataFile^)); { Position for write }
  165.         F.Mode := fmOutput; { Switch to write mode }
  166.         F.InOutFunc := @UnixWrite;
  167.         F.FlushFunc := @UnixWriteFlush;
  168.       end;
  169.     fmOutput:
  170.       begin
  171.         Rewrite(Unix^.DataFile^, 1);
  172.         F.InOutFunc := @UnixWrite;
  173.         F.FlushFunc := @UnixWriteFlush;
  174.       end;
  175.   end;
  176.   F.BufPos := 0; { Reset buffer indexes }
  177.   F.BufEnd := 0;
  178.   UnixOpen := IOResult; { Return IO result from Reset, Rewrite or Append }
  179. end;
  180.  
  181. function UnixClose(var F: TTextRec): Integer; far;
  182. { - Close Unix file }
  183. var
  184.   Unix: pUnixRec;
  185. begin
  186.   Unix := @F.UserData;
  187.   Close(Unix^.DataFile^); { Close the file }
  188.   Dispose(Unix^.DataFile); { free up allocations }
  189.   Unix^.DataFile := nil;
  190.   FreeMem(Unix^.ReadBuf, F.BufSize);
  191.   Unix^.ReadBuf := nil;
  192.   FreeMem(F.BufPtr, F.BufSize);
  193.   F.BufPtr := nil;
  194.   UnixClose := IOResult;
  195. end; { FUNC UnixClose }
  196.  
  197. procedure AssignUnix(var F: Text; name: string; BufferSize: Word);
  198. { - Assign a text file to the unix device driver }
  199. var
  200.   TRec: TTextRec absolute F;
  201. begin
  202.   FillChar(TRec, SizeOf(TRec), 0); { Clean out the TTextRec }
  203.   TRec.OpenFunc := @UnixOpen; { Assign the device driver functions }
  204.   TRec.InOutFunc := nil;
  205.   TRec.FlushFunc := nil;
  206.   TRec.CloseFunc := @UnixClose;
  207.   TRec.Mode := fmClosed; { Initial file mode must be closed }
  208.   if BufferSize > MaxUnixBufferSize { Init the buffer size }
  209.   then BufferSize := MaxUnixBufferSize
  210.    else if BufferSize < 2 * UnixFlushTreshold
  211.     then BufferSize := 2 * UnixFlushTreshold;
  212.   TRec.BufSize := BufferSize and $FFFE; { Ensure even size }
  213.   Move(name[1], TRec.Name, Length(name)); { and the filename }
  214. end; { PROC AssignUnix }
  215.  
  216. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement