home *** CD-ROM | disk | FTP | other *** search
-
- {$I direct.inc}
- {───────────────────────────────────────────────────────────────────────────}
- { FLISTU.PAS File list unit }
- { }
- { Copyright (C) 1988 Lane H.Ferris All Rights Reserved }
- {───────────────────────────────────────────────────────────────────────────}
- { Dinsaurs live }
- {───────────────────────────────────────────────────────────────────────────}
- unit FLISTU ;
- {────────────────────────────────────────────────────────────────────────}
- interface
- {────────────────────────────────────────────────────────────────────────}
-
- type
- filenamestr = string[64] ;
-
- Function FLopen (pFilename : filenamestr ) : integer ;
- Procedure FLclose (pFilename : filenamestr ) ;
- Procedure FLgetNr (pLineNr :word; var Strptr:string ) ;
-
- {────────────────────────────────────────────────────────────────────────}
- implementation
- {────────────────────────────────────────────────────────────────────────}
- uses macros ,
- SR50subs ,
- sr50 {debugging only} ;
-
- type
-
- SeekLstptr = ^SeekLstType ;
- SeekLstType = record { Seek Chain Entry }
- SeekLink : SeekLstptr ; { addr of next entry or nil }
- SeekLineNr : word ; { Line Nr at this location }
- SeekLastNr : word ; { Last Line number in buf }
- SeekFileLoc : longint ; { Byte location within file }
- Seektextlth : word ; { actual text bytes in buf }
- {SeekLstType} end ;
- FLbitmap = array[0..511] of byte ;
-
- const
- FLhasopenfile : boolean = false ;
- _4K = 4*1024 ; { Blk file buffer size }
- crlf : word = $0A0D ; { word of cr lf }
- var
- FLfilename : filenamestr ; { last opened file }
- FLinfile : file ; { File of byte }
- FLfilesize : longint ; { Nr bytes in file }
- FlBufptr : pointer ; { ptr to file buffer }
- FLmapptr : ^FLbitmap ; { 1 bit for each txtrec }
- FLbytesinbuf : word ; { bytes in blk buffer }
- SeekLstAnchor : SeekLstPtr ; { Anchor for Seek list }
- BufSeekLst : SeekLstptr ; { List represented in buf}
- {────────────────────────────────────────────────────────────────────────}
- { SetLastLineNr }
- {────────────────────────────────────────────────────────────────────────}
- { count down the buffer for crlf and return last line number found }
- { set a bit in a large bitstring to indicate where a line exists }
- {────────────────────────────────────────────────────────────────────────}
- Procedure SetLastLineNr (pLstptr : SeekLstptr ) ;
- var
- locptr :SeekLstptr ;
- txtlines :word ;
- txtptr :pointer ;
- Mapbyteptr :^byte ;
- i,j :word ;
- begin
- locptr := pLstptr ;
- txtptr := FLbufptr ;
- txtlines := 0 ;
- pLstptr^.SeekTextlth := 0 ;
- fillchar(FLmapptr^, { say no text with crlf }
- sizeof(FLmapptr^),0) ;
- FLmapptr^[0] := $80 ; { set bit for first record }
- for i := 0 to FLbytesinbuf do begin { scan for more records }
- if word(txtptr^) = crlf then begin
- inc(txtlines) ;
- pLstptr^.Seektextlth := i+2 ;
- j := i+2 ; { beginning of next txt rec }
- Mapbyteptr := ptr(vec(FLmapptr).seg,vec(FLmapptr).ofs+(j DIV 8)) ;
- Mapbyteptr^ := Mapbyteptr^ or ($80 shr (j MOD 8)) ; { set bit }
- end {if word..} ;
- incptr(txtptr,1) ;
- end ;
- pLstptr^.SeeklastNr := pLstptr^.SeekLineNr+txtlines-1 ;
- end { Procedure SetLastLineNr } ;
- {────────────────────────────────────────────────────────────────────────}
- { FLclose }
- {────────────────────────────────────────────────────────────────────────}
- Procedure FLclose(pFilename : filenamestr ) ;
- var
- seekptr : Seeklstptr ;
- begin
- close(FLinfile) ;
- if IOresult <> 0 then
- Errormsg(warnlevel, 'FLopen cannot close '+ pfilename ) ;
- while SeekLstAnchor <> nil do { free all seeklist entries }
- begin
- seekptr := SeekLstAnchor^.seeklink ;
- dispose(SeekLstAnchor) ;
- SeekLstAnchor := seekptr ;
- end {while..};
- freemem(FLbufptr,_4K) ; { memory for Block file buf }
- freemem(FLmapptr,sizeof(Flmapptr^)) ; { memory for txtrec bitmap }
- FLhasopenfile := false ;
- end {FLclose} ;
- {────────────────────────────────────────────────────────────────────────}
- { FLopen }
- {────────────────────────────────────────────────────────────────────────}
- Function FLopen (pFilename : filenamestr ) : integer ;
- var
- Openresult : integer ;
- begin
- {$I-}
- if FLhasopenfile then
- FLclose(FLFilename) ; { close previous file }
- FLfilename := pFilename ;
- assign( FLinfile, pFilename ) ; { open new file }
- reset ( FLinfile,1 ) ;
- {$I+}
- Openresult := IOresult ;
- FLopen := Openresult ;
- if Openresult <> 0 then begin
- Errormsg(warnlevel, 'FLopen: cannot open '+pFilename ) ;
- exit ;
- end {if ioresult} ;
- FLhasopenfile := true ;
- FLfilesize := filesize(FLinfile) ;
- If Maxavail < _4K+512 then begin
- errormsg(warnlevel,'FLopen: Heap overflow') ;
- FlOpen := 203 ; exit ;
- end ;
- getmem(FLbufptr,_4K) ; { memory for Block file buf }
- getmem(FLmapptr, { memory for txtrec bitmap }
- sizeof(FLmapptr^)) ;
- fillchar(FLmapptr^,
- sizeof(FLmapptr^),0) ; { say no text with crlf }
- if FLbufptr = nil then begin
- Errormsg(warnlevel, 'FLopen: no memory for File buffer') ;
- FLclose(Flfilename) ;
- FLhasopenfile := false ;
- exit ;
- end {if nil..} ;
- { prime the input buffer }
- Blockread(FLinfile,FLbufptr^,_4k,Flbytesinbuf) ;
- new(SeekLstAnchor) ; { anchor list of seek locs }
- with SeekLstAnchor^ do begin
- SeekLink := nil ;
- SeekLineNr := 1 ;
- SeekFileloc := 0 ;
- SetLastLineNr(SeekLstAnchor); { scan and set last line Nr }
- end {with SeekLstAnchr} ;
- BufSeekLst := SeekLstAnchor ; { Current List in buffer }
-
- end {Procedure FLopen} ;
-
- {────────────────────────────────────────────────────────────────────────}
- { FLbufread }
- {────────────────────────────────────────────────────────────────────────}
- { Reads another buffer of text from the physical file }
- {────────────────────────────────────────────────────────────────────────}
- Procedure FLbufread (pLineNr : word ) ;
- var
- locptr : SeekLstptr ;
- done : boolean ;
- begin
- locptr := SeekLstAnchor ;
- done := false ;
-
- while
- (locptr^.SeekLink <> nil) and
- (NOT done) do { search SeekLine list to find }
- with locptr^ do { lower linenumber than requested }
- if SeekLink^.SeekLineNr { parameter line number }
- > pLineNr then done := true
- else locptr := SeekLink ;
- { locptr now has low linenumber }
- if locptr^.Seektextlth = 0 then { Check for End of file }
- begin
- BufSeekLst := locptr ;
- exit ; end ;
-
- if locptr^.SeekLastNr >= pLineNr
- then {ok} { pLineNr is within this buffer }
- else begin { else have to read forward }
- new(locptr^.SeekLink) ; { allocate another list entry }
- locptr^.seeklink^ := Locptr^ ; { fill in the Seeklist entry }
- locptr := locptr^.seeklink ; { point to new seeklist entry }
- locptr^.seeklink := nil ;
- locptr^.SeekLineNr := locptr^.SeekLastNr+1 ; { next file line Nr }
- locptr^.SeekFileLoc := Locptr^.SeekFileloc { Seek file byte from.. }
- + Locptr^.SeekTextlth ; { last seek + full lines}
- end {else begin} ;
- { VM386 bug: 06 error if directory is changed }
- Seek(FLinfile,locptr^.SeekFileLoc) ;
- unfreeze;
- if IOresult <> 0 then
- Errormsg(warnlevel, 'FLread: seek error in '+FLFilename ) ;
-
- Blockread(FLinfile,FLbufptr^,_4k,FLbytesinbuf) ;
- SetLastLineNr(locptr) ; { scan and set last line Nr }
- BufSeekLst := locptr ; { current SeekLst in buffer }
- end { Procedure FLbufread } ;
- {────────────────────────────────────────────────────────────────────────}
- { BitScanOfs }
- {────────────────────────────────────────────────────────────────────────}
- { bitcount := BitScanofs(FLmapptr^,size(FLmapptr^),bitcount) ; }
- { scans a large bit string and returns position of next bit }
- {────────────────────────────────────────────────────────────────────────}
- Function BitScanOfs(BitMapPtr : pointer;
- BitMapsize,bitcount :word) :word ;
- Begin
- Inline(
- $29/$D2 { sub dx,dx ;}
- /$8B/$86/>BITCOUNT { mov ax,[bp+>bitcount] ; position of last bit returned}
- /$B9/$08/$00 { mov cx,8 ;}
- /$F7/$F1 { div cx ; position of byte last returned}
- /$89/$D1 { mov cx,dx ; save bitpos MOD 8}
- /$89/$C3 { mov bx,ax ; save offset to byte}
- /$C4/$BE/>BITMAPPTR { les di,[bp+>BitMapPtr] ; pointer to full bitstring}
- /$01/$DF { add di,bx ; point to byte}
- /$26 { es: ;}
- /$FF/$35 { push [di] ; save the current byte}
- /$57 { push di ; save the ofs to it}
- /$B0/$FF { mov al,$FF ;}
- /$D2/$E8 { shr al,cl ; 0 bits ahead/1 bits behind old bit}
- /$26 { es: ;}
- /$20/$05 { and 0[di],al ; kill the bit last returned}
- /$29/$C0 { sub ax,ax ; scan for a byte containing a bit}
- /$8B/$8E/>BITMAPSIZE { mov cx,[bp+>BitMapsize];}
- /$F3/$AE { repe scasb ; repeat while equal to zero}
- /$4F { dec di ; set pointer to last byte}
- /$26 { es: ;}
- /$8A/$1D { mov bl,0[di] ; fetch byte}
- /$2B/$BE/>BITMAPPTR { sub di,[bp+>BitMapPtr] ; fetch byte count scanned}
- /$29/$D2 { sub dx,dx ;}
- /$89/$F8 { mov ax,di ;}
- /$B9/$08/$00 { mov cx,8 ;}
- /$F7/$E1 { mul cx ; now have bit count}
- { ; now add bits in the stop byte}
- /$D0/$E3 {L1: sal bl,1 ; shift out any bit that may be there}
- /$72/$03 { jc L2 ; carry if bit is shifted out}
- /$40 { inc ax ; count the non-bit}
- /$E2/$F9 { loop L1 ; shift until we find the bit}
- /$5F {L2: pop di ; replace the modified bit pattern}
- /$26 { es: ;}
- /$8F/$05 { pop [di] ;}
- /$89/$46/$FE { mov [bp-2],ax ; stow the function return value}
- ) ;
- End {BitScanOfs} ;
- {────────────────────────────────────────────────────────────────────────}
- { MaptoBufofs }
- {────────────────────────────────────────────────────────────────────────}
- { Search for a bit in the buffer bit map which }
- { represents this line number. Return its offset in buffer }
- {────────────────────────────────────────────────────────────────────────}
- Function MaptoBufofs (pLineNr :word) :word ;
- var
- i :word ;
- bitcount :word ;
- maxbits :word ;
- Begin
-
- { scan the bit map until we find pLineNr bit }
- { there is always at least one bit, viz, the first line in buffer bit }
-
- i := BufSeekLst^.SeekLineNr-1 ; { first lineNr in this buffer }
- bitcount := 0 ;
- maxbits := sizeof(FLmapptr^)*8 ; { number of slots in bitmap }
- MaptoBufofs := 0 ;
- REPEAT
- bitcount := BitScanofs(FLmapptr,sizeof(FLmapptr^),bitcount) ;
- if bitcount <= maxbits then inc(i) ;
- if i >= pLineNr then begin
- MaptoBufofs := bitcount ; { a bit displacement and a byte }
- exit ; { displacement are equivalent }
- end ;
- inc(bitcount) ; { dont read old bit again }
- UNTIL (bitcount >= maxbits) ;
-
- End { MaptoBufofs } ;
- {────────────────────────────────────────────────────────────────────────}
- { FLgetNr }
- {────────────────────────────────────────────────────────────────────────}
- { Search for Line Nr in current buffer }
- { Search for Line number , return actual line nr found }
- {────────────────────────────────────────────────────────────────────────}
- Procedure FLgetNr (pLineNr :word; var Strptr:string ) ;
- var
- Seekptr : SeekLstptr ;
- Hdptr : pointer ;
- Edptr : pointer ;
- found : boolean ;
- Outstr : string absolute Strptr ;
- thisnr : word ;
- txtlth : word ;
-
- begin
- Seekptr := BufSeekLst ;
- found := false ;
-
- while NOT found do begin
- if ((pLineNr >= seekptr^.SeekLineNr) { read another buffer when }
- and { line nr not in current buf }
- (pLineNr <= seekptr^.SeekLastNr))
- then found := true ;
- if NOT found then begin
- FLbufread(pLineNr) ;
- seekptr := BufSeekLst ;
- end {if..} ;
- if seekptr^.seektextlth = 0 { check for end of file }
- then found := true ;
- end {while} ;
-
- Hdptr := FlBufptr ; { search for desired line Nr }
- Edptr := Hdptr ; { search for a its bit in map }
- thisnr := seekptr^.SeekLineNr ;
-
- incptr(Hdptr, MaptoBufofs(pLineNr )) ;
- incptr(Edptr, MaptoBufofs(pLineNr+1 )) ;
- txtlth := ptrdiff(Edptr,Hdptr) ;
- if txtlth > 255 then txtlth := 255 ;
-
- Outstr[0] := char(txtlth) ;
- move(Hdptr^,Outstr[1],txtlth) ;
-
- if txtlth > 0 then {found ok} { return ptr if LineNr found }
- else begin { else return EOF indication }
- str(seekptr^.SeekLastNr,OutStr) ;
- Outstr := #26+Outstr ;
- end ;
-
- end { Procedure FLgetNr } ;
- {────────────────────────────────────────────────────────────────────────}
- { initialization }
- {────────────────────────────────────────────────────────────────────────}
-
- begin { FLST initialization }
- SeekLstAnchor := nil ;
- end { FLST initialization } .