{ 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}