[Back to TEXTFILE SWAG index]  [Back to Main SWAG index]  [Original]

{
From: LEE LEFLER
Subj: Shared textfiles

 Want to do some reading of LARGE textfiles on a network.
 How can I open a textfile for reading in
 (readonly+denywrite) mode ?

  Some say that Text files can't be shared ?!?!?

      Sure they can, but it takes a little special work to do it.  I use
the following unit to share the nodelist.  I don't know who originally wrote it
so I hope it's OK to post.  It's going to need a little cleaning up since the
message readers are going to wrap it, but I don't want to modify it so you guys
will have to handle that when you export it.
}

Unit TxtShare;

{$F+}

{ This UNIT implements a TEXT file device driver to access TEXT files with a }
{ user specified network access mode (see DOS Technical Reference for DOS }
{ function 3Dh).  This can be accomplished for non-TEXT files by setting the }
{ standard global variable "FileMode" (part of the System unit) to the desired
}
{ value, and then calling the appropriate open function. This is not supported
}
{ for TEXT files in Turbo Pascal v4.0. }

{ To open a Text file with a user specified access mode, place a call to the }
{ procedure AssignText to associate a filename with the text file variable. }
{ Next, set the standard global variable FileMode with the desired DOS access }
{ mode value.  RESET, REWRITE, and APPEND will now use the access mode }
{ assigned to the FileMode variable when opening the file. }

{ By default, no EOF marker is written to text files that have been "assigned"
}
{ using this unit's routines.  If you require a ^Z at the end of any file }
{ opened for output, set the global variable WriteTextEofChar to TRUE before }
{ closing the file. }

Interface

Uses Dos;

Var
   WriteTextEofChar : Boolean;

Procedure AssignText(Var F : Text; FileName : String);

Implementation

{$R-,S-}

Var
   ReadText_Addr  : Pointer;
   WriteText_Addr : Pointer;
   SeekText_Addr  : Pointer;
   DoNothing_Addr : Pointer;
   CloseText_Addr : Pointer;

Function ReadText(Var F : TextRec) : Word;
Begin
   Inline(
     $1E/                   {       push     ds          ;Save data segment
value}
     $C5/$76/$06/           {       lds      si,[bp+6]   ;Address the file var
structure}
     $AD/                   {       lodsw                ;Pick up file handle}
     $89/$C3/               {       mov      bx,ax       ; ... and store in bx}
     $46/                   {       inc      si          ;Skip past the Mode
field}
     $46/                   {       inc      si          ; ... and address the
BufSize field}
     $AD/                   {       lodsw                ;Pick up BufSize (# of
bytes to read)}
     $89/$C1/               {       mov      cx,ax       ; ... and store in cx}
     $81/$C6/$06/$00/       {       add      si,6        ;Address the BufPtr
field}
     $AD/                   {       lodsw                ;Pick up Offset part
of the pointer}
     $89/$C2/               {       mov      dx,ax       ; ... and store in dx}
     $AD/                   {       lodsw                ;Pick up Segment part
of the pointer}
     $8E/$D8/               {       mov      ds,ax       ; ... and store in ds}
     $B4/$3F/               {       mov      ah,$3F      ;DOS Read a
File/Device function}
     $CD/$21/               {       int      $21         ;Call DOS}
     $72/$0F/               {       jc       Error       ;Error if Carry Flag
set}
     $50/                   {       push     ax          ;Save # of bytes
actually read}
     $31/$C0/               {       xor      ax,ax       ;Clear ax to zero}
     $C4/$7E/$06/           {       les      di,[bp+6]   ;Address the file var
structure}
     $81/$C7/$08/$00/       {       add      di,8        ;Address the BufPos
field}
     $AB/                   {       stosw                ;Store 0 in the BufPos
field}
     $58/                   {       pop      ax          ;Retrieve bytes
actually read}
     $AB/                   {       stosw                ; ... and store in
BufEnd field}
     $31/$C0/               {       xor      ax,ax       ;Return 0 ==> no
errors}
     $1F/                   {Error: pop      ds          ;Restore ds value}
     $89/$46/$FE);          {       mov      [bp-2],ax   ;Store returned value}
End {ReadText};

Function WriteText(Var F : TextRec) : Word;
Begin
   Inline(
     $1E/                   {       push     ds          ;Save value of data
seg register}
     $C5/$76/$06/           {       lds      si,[bp+6]   ;DS:SI points to
TextRec structure}
     $AD/                   {       lodsw                ;Pick up file handle}
     $89/$C3/               {       mov      bx,ax       ; ... and store in BX}
     $81/$C6/$06/$00/       {       add      si,6        ;DS:SI points to
BufPos field}
     $AD/                   {       lodsw                ;Pick up # of bytes to
write}
     $89/$C1/               {       mov      cx,ax       ; ... and store in CX}
     $46/                   {       inc      si}
     $46/                   {       inc      si          ;DS:SI points to
BufPtr field}
     $AD/                   {       lodsw                ;Pick up offset part
of buffer addr.}
     $89/$C2/               {       mov      dx,ax       ; ... and store in DX}
     $AD/                   {       lodsw                ;Pick up segment part
of buffer addr.}
     $8E/$D8/               {       mov      ds,ax       ; ... and store in DS}
     $B4/$40/               {       mov      ah,$40      ;DOS write file/device
function}
     $CD/$21/               {       int      $21         ;Call DOS}
     $72/$0B/               {       jc       Error       ;Error if Carry Flag
is set on return}
     $31/$C0/               {       xor      ax,ax       ;Clear AX to zero}
     $C4/$7E/$06/           {       les      di,[bp+6]   ;ES:DI points to
TextRec structure}
     $81/$C7/$08/$00/       {       add      di,8        ;ES:DI points to
BufPos field}
     $AB/                   {       stosw                ;Reset BufPos to zero}
     $AB/                   {       stosw                ;Reset BufEnd to zero}
     $1F/                   {Error: pop      ds          ;Restore data seg
register}
     $89/$46/$FE);          {       mov      [bp-2],ax   ;Store function
result}
End {WriteText};

Function DoNothing(Var F : TextRec) : Word;
Begin
   Inline(
     $C7/$46/$FE/$00/$00);    {        mov    word [bp-2],0}
End {DoNothing};

Function SeekEofText(Var F : TextRec) : Word;
Begin
   Inline(
     $1E/                     {        push     ds                   ;Save Data
Seg register}
     $C4/$7E/$06/             {        les      di,[bp+6]            ;ES:DI
points to the TextRec}
     $26/$8B/$1D/             {    es: mov word bx,[di]              ;File
handle into BX}
     $31/$C9/                 {        xor      cx,cx                ;CX:DX =
Offset for Seek function}
     $89/$CA/                 {        mov      dx,cx                ;With AL=2
and CX:DX=0, will seek eof}
     $B8/$02/$42/             {        mov      ax,$4202}
     $CD/$21/                 {        int      $21                  ;DX:AX
should now contain filesize}
     $72/$7B/                 {        jc       Error}
     $2D/$80/$00/             {        sub      ax,128
;Reposition to read the last 128 bytes of}
     $81/$DA/$00/$00/         {        sbb      dx,0                 ;the file
(or as much as we can)}
     $79/$04/                 {        jns      NonNeg               ;If less
than 128 chars in file}
     $31/$C0/                 {        xor      ax,ax                ;  then
just read from beginning}
     $89/$C2/                 {        mov      dx,ax}
     $89/$D1/                 {NonNeg: mov      cx,dx                ;Set up
for Seek function}
     $89/$C2/                 {        mov      dx,ax                ;CX:DX =
Absolute position to seek}
     $26/$89/$55/$20/         {    es: mov word [di+32],dx           ;Save in
UserData field for later}
     $26/$89/$4D/$22/         {    es: mov word [di+34],cx}
     $26/$8B/$1D/             {    es: mov word bx,[di]              ;File
handle in BX}
     $B8/$00/$42/             {        mov      ax,$4200             ;Dos seek
(absolute) function}
     $CD/$21/                 {        int      $21}
     $72/$58/                 {        jc       Error}
     $06/                     {        push     es                   ;Set up
for call to read by pushing}
     $57/                     {        push     di                   ;TextRec
address onto stack}
     $FF/$1E/>READTEXT_ADDR/  {        call far [>ReadText_Addr]     ;Read the
file}
     $09/$C0/                 {        or       ax,ax                ;Any
errors?}
     $75/$4E/                 {        jnz      Error}
     $C5/$76/$06/             {        lds      si,[bp+6]            ;Use DS:SI
as TextRec ptr}
     $8B/$4C/$0A/             {        mov word cx,[si+10]           ;CX = #
bytes read}
     $E3/$44/                 {        jcxz     Done                 ;If 0
bytes read, then we're done}
     $8B/$44/$0C/             {        mov word ax,[si+12]           ;BufPtr
offset}
     $89/$C7/                 {        mov      di,ax                ;ES:DI
will point at the buffer of data}
     $4F/                     {        dec      di                   ;  that
was just read in}
     $01/$CF/                 {        add      di,cx}
     $8B/$44/$0E/             {        mov word ax,[si+14]}
     $8E/$C0/                 {        mov      es,ax}
     $B0/$1A/                 {        mov      al,$1A}
     $FD/                     {        std}
     $F2/$AE/                 {  repnz scasb                         ;Search
buffer for a ^Z}
     $FC/                     {        cld}
     $75/$2F/                 {        jnz      Done                 ;If no ^Z
found, then we're done}
     $C4/$7E/$06/             {        les      di,[bp+6]            ;Back to
using ES:DI for TextRec}
     $1F/                     {        pop      ds                   ;Point DS
back at global variable segment}
     $1E/                     {        push     ds                   ;But push
back for final pop}
     $89/$C8/                 {        mov      ax,cx                ;ax=offset
in buffer at which ^Z was found}
     $26/$8B/$55/$20/         {    es: mov word dx,[di+32]           ;Retrieve
saved file ptr pos.}
     $26/$8B/$4D/$22/         {    es: mov word cx,[di+34]}
     $01/$C2/                 {        add      dx,ax                ;Add in
offset of ^Z}
     $81/$D1/$00/$00/         {        adc      cx,0}
     $26/$8B/$1D/             {    es: mov word bx,[di]              ;file
handle back in BX}
     $B8/$00/$42/             {        mov      ax,$4200             ;Again
with the Seek function}
     $CD/$21/                 {        int      $21
;Reposition file pointer to ^Z char}
     $72/$12/                 {        jc       Error}
     $26/$C7/$44/$08/$00/$00/ {    es: mov word [si+8],0             ;BufPos=0
(write 0 bytes to truncate ...}
     $06/                     {        push     es                   ; ... the
file at the ^Z)}
     $57/                     {        push     di                   ;Setup for
call to write routine}
     $FF/$1E/>WRITETEXT_ADDR/ {        call far [>WriteText_Addr]}
     $09/$C0/                 {        or       ax,ax                ;Any
errors}
     $75/$02/                 {        jnz      Error}
     $31/$C0/                 {Done:   xor      ax,ax                ;Return 0
if no errors}
     $1F/                     {Error:  pop      ds}
     $89/$46/$FE);            {        mov      [bp-2],ax}
End {SeekEofText};

Function CloseText(Var F : TextRec) : Word;
Begin
   Inline(
     $1E/                           {         push     ds
;Must preserve DS for return}
     $C4/$7E/$06/                   {         les      di,[bp+6]
;ES:DI is our ptr to the TextRec}
     $26/$8B/$44/$02/               {     es: mov      ax,[si+2]
;Magic Number into AX}
     $3D/>FMOUTPUT/                 {         cmp word ax,>fmOutput
;File opened with Rewrite or Append?}
     $75/$2D/                       {         jnz      SkipEof
;No, skip ^Z stuff}
     $80/$3E/>WRITETEXTEOFCHAR/$01/ {         cmp byte [>WriteTextEofChar],1
;Use ^Z to mark end of file?}
     $75/$26/                       {         jnz      SkipEof
;No, skip ^Z stuff}
     $26/$8B/$45/$0C/               {     es: mov word ax,[di+12]
;Get address of output buffer}
     $26/$8B/$5D/$0E/               {     es: mov word bx,[di+14]}
     $89/$C7/                       {         mov      di,ax}
     $8E/$C3/                       {         mov      es,bx
;ES:DI points to buffer now}
     $B8/$1A/$00/                   {         mov      ax,$1A}
     $AB/                           {         stosw
;Put a ^Z into the buffer}
     $C4/$7E/$06/                   {         les      di,[bp+6]
;Point ES:DI back at the TextRec}
     $26/$C7/$45/$08/$01/$00/       {     es: mov word [di+8],1
;Set BufPos to show 1 char to write}
     $06/                           {         push     es
;Put TextRec Address onto stack}
     $57/                           {         push     di}
     $FF/$1E/>WRITETEXT_ADDR/       {         call far [>WriteText_Addr]
;Call Write routine to write the ^Z}
     $09/$C0/                       {         or       ax,ax
;Any problems with the write?}
     $75/$1D/                       {         jnz      Error
;Yes, exit with error code in AX}
     $C4/$7E/$06/                   {         les      di,[bp+6]
;ES:DI probably trashed in call}
                                    {SkipEof:}
     $26/$8B/$1D/                   {     es: mov      bx,[di]
;File handle in BX}
     $B8/$00/$3E/                   {         mov      ax,$3E00
;Dos Close function}
     $CD/$21/                       {         int      $21
;Close the file}
     $72/$10/                       {         jc       Error
;If error, exit with code in AX}
     $31/$C0/                       {         xor      ax,ax}
     $26/$89/$45/$08/               {     es: mov word [di+8],ax
;Stuff zeros in BufPos and BufEnd}
     $26/$89/$45/$0A/               {     es: mov word [di+10],ax}
     $26/$C7/$45/$02/>FMCLOSED/     {     es: mov word [di+2],>fmClosed
;Reset the magic number}
     $1F/                           {Error:   pop      ds}
     $89/$46/$FE);                  {         mov      [bp-2],ax
;Store function result}
End {CloseText};

Function OpenText(Var F : TextRec) : Word;
Begin
   Inline(
     $1E/                       {         push      ds                  ;Save
DS register}
     $C4/$7E/$06/               {         les       di,[bp+6]           ;ES:DI
is pointer to the TextRec structure}
     $B4/$3D/                   {Start:   mov       ah,$3D              ;DOS
open a file/device function}
     $26/$81/$7D/$02/>FMOUTPUT/ {     es: cmp word  [di+2],>fmOutput    ;Open
for Rewrite?}
     $75/$02/                   {         jnz       OpenIt              ;No,
skip next line}
     $B4/$3C/                   {         mov       ah,$3C              ;DOS
create new/truncate old file}
     $A0/>FILEMODE/             {OpenIt:  mov       al,[>FileMode]      ;Put
user specified access mode in AL}
     $B9/$00/$00/               {         mov       cx,0                ;File
attribute (nothing special) in CX}
     $8C/$C3/                   {         mov       bx,es}
     $8E/$DB/                   {         mov       ds,bx}
     $89/$FA/                   {         mov       dx,di}
     $81/$C2/$30/$00/           {         add       dx,48               ;DS:DX
points to asciiz filename}
     $CD/$21/                   {         int       $21                 ;Open
the file}
     $1F/                       {         pop       ds
;Restore DS to segment with global vars}
     $1E/                       {         push      ds                  ; ...
and save back on stack for later}
     $73/$15/                   {         jnc       OpenOk              ;If no
errors, continue}
     $3D/$02/$00/               {         cmp       ax,2                ;File
not found?}
     $75/$69/                   {         jnz       Error               ;No,
exit with error code in ax}
     $26/$81/$7D/$02/>FMINOUT/  {     es: cmp word  [di+2],>fmInOut     ;Opened
for Append?}
     $75/$61/                   {         jnz       Error               ;No,
exit with error code in ax}
     $26/$C7/$45/$02/>FMOUTPUT/ {     es: mov word  [di+2],>fmOutput    ;No
existing file to append ...}
     $EB/$C9/                   {         jmp short Start               ; ...
so try again with Rewrite}
     $AB/                       {OpenOk:  stosw                         ;Store
file handle (in AX) into TextRec}
     $BE/>CLOSETEXT_ADDR/       {         mov       si,>CloseText_Addr  ;DS:SI
points at addr. of CloseText fn.}
     $81/$C7/$1A/$00/           {         add       di,26               ;ES:DI
points to CloseFunc field}
     $B9/$02/$00/               {         mov       cx,2                ;Double
word address to move}
     $F2/$A5/                   {     rep movsw                         ;Store
address into CloseFunc field}
     $C4/$7E/$06/               {         les       di,[bp+6]           ;ES:DI
back to pointing at TextRec}
     $26/$81/$7D/$02/>FMINOUT/  {     es: cmp word  [di+2],>fmInOut     ;Opened
with Append?}
     $75/$13/                   {         jnz       NoSeek              ;No,
skip the search for ^Z}
     $06/                       {         push      es                  ;Set up
stack for call to SeekEofText}
     $57/                       {         push      di                  ;Addr
of TextRec goes on the stack}
     $FF/$1E/>SEEKTEXT_ADDR/    {         call far  [>SeekText_Addr]    ;Get
rid of any ^Z at end of file}
     $09/$C0/                   {         or        ax,ax               ;Any
errors?}
     $75/$37/                   {         jnz       Error               ;Yes,
exit with error code in AX}
     $C4/$7E/$06/               {         les       di,[bp+6]
;Restore ptr to TextRec trashed in call}
     $26/$C7/$45/$02/>FMOUTPUT/ {     es: mov word  [di+2],>fmOutput    ;Reset
TextRec mode to show output only}
                                {NoSeek:}
     $26/$C7/$45/$08/$00/$00/   {     es: mov word  [di+8],0            ;Set
BufPos to 0}
     $26/$C7/$45/$0A/$00/$00/   {     es: mov word  [di+10],0           ;Set
BufEnd to 0}
     $26/$81/$7D/$02/>FMINPUT/  {     es: cmp word  [di+2],>fmInput     ;Opened
with reset?}
     $74/$05/                   {         jz        InFunc              ;Yes,
set pointers accordingly}
     $BE/>WRITETEXT_ADDR/       {         mov       si,>WriteText_Addr  ;DS:SI
--> Address of WriteText func.}
     $EB/$03/                   {         jmp short SetFunc             ;Go set
TextRec function pointers}
     $BE/>READTEXT_ADDR/        {InFunc:  mov       si,>ReadText_Addr   ;DS:SI
--> Address of ReadText func.}
     $81/$C7/$14/$00/           {SetFunc: add       di,20               ;ES:DI
--> InOutFunc field}
     $B9/$02/$00/               {         mov       cx,2                ;Moving
a double word}
     $51/                       {         push      cx                  ;Save
this count for later}
     $F2/$A5/                   {     rep movsw                         ;Store
address of I/O routine}
     $BE/>DONOTHING_ADDR/       {         mov       si,>DoNothing_Addr  ;DS:SI
--> Address of DoNothing func.}
     $59/                       {         pop       cx                  ;ES:DI
--> FlushFunc field - move 2 words}
     $F2/$A5/                   {     rep movsw                         ;Store
address of flush routine}
     $31/$C0/                   {         xor       ax,ax               ;No
errors, return a 0 to caller}
     $1F/                       {Error:   pop       ds
;Restore DS register}
     $89/$46/$FE);              {         mov       [bp-2],ax           ;Store
function result}
End {OpenText};

Procedure AssignText(Var F : Text; FileName : String);
Var
   I : Integer;
Begin
   With TextRec(F) do begin               { Initialize textrec record         }
      Handle   := $FFFF;                  { Set file handle to junk           }
      Mode     := fmClosed;               { Indicate the file is not yet open }
      BufSize  := SizeOf(Buffer);         { Set size of default buffer (128)  }
      BufPtr   := @Buffer;                { Set up pointer to default buffer  }
      OpenFunc := @OpenText;              { Set up pointer to OPEN function   }
      For I := 1 to Length(FileName) do   { Set up asciiz filename            }
         Name[I-1] := FileName[I];
      Name[Length(FileName)] := Chr(0);
   End {with};
End {AssignText};

Begin
   { Initialize global variable to suppress writing ^Z at the end of any     }
   { text file opened with Append or Rewrite.                                }
   WriteTextEofChar := FALSE;

   { Initialize internally used Address variables (pointers)                 }
   ReadText_Addr    := Addr(ReadText);
   WriteText_Addr   := Addr(WriteText);
   SeekText_Addr    := Addr(SeekEofText);
   DoNothing_Addr   := Addr(DoNothing);
   CloseText_Addr   := Addr(CloseText);
End {Unit TxtShare}.

{$F-}

{end}

[Back to TEXTFILE SWAG index]  [Back to Main SWAG index]  [Original]