[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]