{$I VERSION.PAS - configures for different compilers} {$IFDEF BORPAS} {$M 65520, 0, 655360} {$ELSE} {$UNDEF LFN} {$ENDIF} {$IFDEF DELPHI} {$H-} {$ENDIF} program CHEKLINX { For instructions, now see cheklinx.txt. www.merlyn.demon.co.uk date follows } ; uses {$IFDEF DELPHI} SysUtils {$ELSE} Dos {$ENDIF} {$IFDEF LFN}, LFN {$ENDIF} ; const Today = '2006-01-27' ; { Try to allow for ') ; Readln end ; end {Um} ; procedure Umm(const B : boolean) ; begin if B then Um else Writeln end {Umm} ; procedure WhyError(const WhyE, Doing : string ; const Error : integer) ; begin Write(WhyE, Space) ; if Viz>Norm then Write(Doing, ': ') ; case Error of 1 : Write('invalid function number') ; 2 : Write('file not found') ; 3 : Write('path not found') ; 4 : Write('too many open files') ; 5 : Write('file access denied') ; 6 : Write('invalid file handle') ; 12 : Write('invalid file access code') ; 15 : Write('invalid drive number') ; 18 : Write({'No more files'}'not found') ; else Write({'unexpected?'}'Error #', Error) ; end ; Um end {WhyError} ; function UpCaseStr(S : string) : string ; var B : byte ; begin for B := 1 to Length(S) do S[B] := UpCase(S[B]) ; UpCaseStr := S end {UpCaseStr} ; function ErrLoc(const S : string ; const N : word) : string ; var S5 : string [5] ; begin Str(N:4, S5) ; ErrLoc := '@ ' + S + Space + S5 ; end {ErrLoc} ; procedure CheckNotEmptyValue(const FN, Got : string ; const LNo : word) ; begin if Got='' then begin Write(ErrLoc(FN, LNo), ' "', Got, '" value empty') ; Um ; Inc(Empty) ; EXIT end ; end {CheckNotEmptyValue} ; procedure Check8_3(const FN, Got : string ; const LNo : word) ; var J, K, L : byte ; begin K := 0 ; L := 8 ; J := 1 ; repeat if K>L then begin Write(ErrLoc(FN, LNo), ' "', Got, '" not 8.3') ; Umm(LongWarn=Lstop) ; Inc(Not8_3) ; EXIT end ; if J>Length(Got) then EXIT ; Inc(K) ; case Got[J] of Spc : K := 255 ; '#' : EXIT ; '.' : if L<>3 then begin K := 0 ; L := 3 end ; '/' : begin K := 0 ; L := 8 end ; end ; Inc(J) until false ; end {Check8_3} ; procedure CheckCase(const FN, Got : string ; const LNo : word) ; var J : byte ; begin for J := 1 to Length(Got) do case Got[J] of 'A'..'Z' : begin Write(ErrLoc(FN, LNo), ' "', Got, '" not lower case') ; Umm(UCWarn=Cstop) ; Inc(UCChars) ; EXIT end ; '#' : EXIT ; end ; end {CheckCase} ; function PartMatch(const S, T : string) : boolean ; var B : byte ; begin PartMatch := false ; B := 1 ; while (B<=Length(S)) and (B<=Length(T)) do if S[B]<>T[B] then EXIT else Inc(B); PartMatch := true end {PartMatch} ; function SeekFileRef(const UpG, Start, Need, Name : string ; var Got : string ; var So : Sort) : boolean ; { Need is for NAME in PARAM } var B : byte ; begin SeekFileRef := false ; if Length(Start)>Length(UpG) then EXIT ; for B := 1 to Length(Start) do if UpG[B]<>Start[B] then EXIT ; if Length(Need)>0 then if Pos(Need, UpG)=0 then EXIT ; B := Pos(Name, UpG) ; if B>0 then begin SeekFileRef := true ; So := Src ; Delete(Got, 1, B+Length(Name)-1) end ; end {SeekFileRef} ; function Hex(const C : char) : byte ; begin Hex := Pred(Pos(UpCase(C), '0123456789ABCDEF')) end {Hex} ; { CRD = Current Relative Directory FB = File Base ? } procedure ExamineInLtGt(var Got : string ; var FB, CRD : S80 ; const Root : PFileList ; const LNo : word) ; var PL : PItem ; PMore, Q : byte ; So : Sort ; Ch : char ; B : boolean ; S4 : string [4] ; UpG : string ; begin UpG := UpCaseStr(Got) ; So := Nun ; repeat if Copy(UpG, 1, 2)='A'+Spc then begin Q := 3 ; while (UpG[Q]=Spc) and (Q<255) do Inc(Q) ; S4 := Copy(UpG, Q, Q+3) ; if S4='HREF' then So := Src else if S4='NAME' then So := Dst ; if So=Nun then begin Inc(OddArefs) ; Write(ErrLoc(Root^.DosFiNa^, LNo), ' eh?') ; Um end {So=Nun} ; Delete(Got, 1, Q+4) ; BREAK end {A HREF=} ; (* *) if (UpG[1]='H') and (UpG[2] in ['1'..'6']) then begin Q := 4 ; while (UpG[Q]=Spc) and (Q<255) do Inc(Q) ; if Copy(UpG, Q, Q+1) ='ID' then So := Dst ; Delete(Got, 1, Q+2) ; BREAK end {Hn ID=} ; (* *) if ParamTest then if Copy(UpG, 1, 6)='PARAM ' then begin if SeekFileRef(UpG, '', 'IMAGE', 'VALUE=', Got, So) then BREAK ; if SeekFileRef(UpG, '', 'FILENAME', 'VALUE=', Got, So) then BREAK ; if SeekFileRef(UpG, '', 'URL', 'VALUE=', Got, So) then BREAK ; if SeekFileRef(UpG, '', 'DATAURL', 'VALUE=', Got, So) then BREAK ; if SeekFileRef(UpG, '', 'SRC', 'VALUE=', Got, So) then BREAK ; if SeekFileRef(UpG, '', 'LINK', 'VALUE=', Got, So) then BREAK ; if SeekFileRef(UpG, '', 'SOURCE', 'VALUE=', Got, So) then BREAK ; if SeekFileRef(UpG, '', 'MOVIE', 'VALUE=', Got, So) then BREAK ; end {PARAM} ; if SeekFileRef(UpG, 'IMG ', '', 'SRC=', Got, So) then BREAK ; if SeekFileRef(UpG, 'SCRIPT ', '', 'SRC=', Got, So) then BREAK ; if SeekFileRef(UpG, 'FRAME ', '', 'SRC=', Got, So) then BREAK ; if SeekFileRef(UpG, 'IFRAME ', '', 'SRC=', Got, So) then BREAK ; if SeekFileRef(UpG, 'EMBED ', '', 'SRC=', Got, So) then BREAK ; if SeekFileRef(UpG, 'AREA ', '', 'HREF=', Got, So) then BREAK ; if SeekFileRef(UpG, 'LINK ', '', 'HREF=', Got, So) then BREAK { CSS } ; if SeekFileRef(UpG, 'APPLET ', '', 'CODE=', Got, So) then BREAK ; { if SeekFileRef(UpG, 'OPTION ', '', 'VALUE=', Got, So) then BREAK { Select } ; if SeekFileRef(UpG, 'META ', '', 'URL=', Got, So) then begin { Writeln('META : *', Got, '*') ; } if Got[Length(Got)] in ['''','"'] then Dec(Got[0]) ; { Writeln('META : *', Got, '*') ; } BREAK end ; if Copy(UpG, 1, 9)='BASE HREF' then begin So := Bas ; Writeln(ErrLoc(Root^.DosFiNa^, LNo), ' not (yet?) fully handled OK ?') ; Delete(Got, 1, 10) ; BREAK end {BASE HREF=} ; until TRUE ; if So=Nun then EXIT ; while (Got>'') and (Got[1]=Spc) do Delete(Got, 1, 1) ; if Got>'' then { reduce to file name } begin Ch := Got[1] ; B := not (Ch in ['"', '''']) ; if B then Pmore := Pos(Spc, Got) else begin Delete(Got, 1, 1) ; Pmore := Pos(Ch, Got) end ; if Pmore>0 then Delete(Got, Pmore, 255) ; if B and (QuoTest>QMiss) then begin Inc(NoQuos) ; Write(ErrLoc(Root^.DosFiNa^, LNo), ' "', Got, '": not in quotes') ; Umm(QuoTest=Qstop) end ; end ; if Copy(Got, 1, 1)='!' then EXIT { See JRS's puzzles.htm ! } ; Pmore := Pos('?', Got) ; if PMore>0 then Delete(Got, PMore, 255) ; if So<>Bas then begin Pmore := Pos(':', Got) ; if Pmore>0 then begin { only use relative references } if (OptB>'') and (Pos(OptB, Got)=1) and (Got<>OptB+Root^.DosFiNa^) then begin Inc(Relables) ; Write(ErrLoc(Root^.DosFiNa^, LNo), ' "', Got, '" make relative?') ; Um ; EXIT end ; if (Pmore<3) or (not (UpCase(Got[Pmore-2]) in ['A'..'Z'])) or (Pos('FILE:', UpCaseStr(Got))>0) then begin if Viz>More then Writeln ; if Viz>Zero then begin Write(ErrLoc(Root^.DosFiNa^, LNo), ' "', Got, '": local?') ; Umm(Colon) ; end ; Inc(LocalURLs) ; EXIT end ; Inc(FarURLs) { presume it is a full URL, so ignore } ; EXIT end ; end {<>Bas} ; if So=Src then if BSwarn and (Pos('\', Got)>0) then begin Write(ErrLoc(Root^.DosFiNa^, LNo), ' "', Got, '" has "\"') ; Inc(BSlash) ; Um end else begin (* CheckNotEmptyValue(Root^.DosFiNa^, Got, LNo) ; *) if LongWarn>Lmiss then Check8_3(Root^.DosFiNa^, Got, LNo) ; if UCWarn>Cmiss then CheckCase(Root^.DosFiNa^, Got, LNo) ; end ; if So in [Src, Dst] then CheckNotEmptyValue(Root^.DosFiNa^, Got, LNo) ; (* Present plan is (/B option is the Web dir of the DOS current directory) 1) to remark on presence of BASE - OK (above). 2) if no /B option, assert that BASE HREF gives the current Web directory - then all works normally. 3) else if BASE HREF equals /B + relative offset, it is as 2). 4) else if BASE HREF equals /B ... might be able to handle it. 5) else if BASE HREF and /B are equal after truncation of longer, apologise for the case being difficult. 6) else express disbelief in one or both strings. *) if So=Bas then begin if Got[Length(Got)]<>'/' then begin Write(' ?? "', Got, '" does not end in "/"') ; Um ; EXIT end ; if OptB='' then begin Writeln(' ?? No OptB : assume that is the current Web directory.') ; EXIT end ; if OptB+CRD=Got then begin Write(' ?? HREF=OptB+CRD : so it is the current Web directory; OK.') ; Um ; EXIT end ; if OptB=Got then begin Write(' ?? HREF=OptB, CRD>"" : use Web root directory; OK?') ; CRD := '' ; Um ; EXIT end ; Writeln(' ?? BASE is "', Got, '"'^M^J' ?? OptB is "', OptB, '"') ; if PartMatch(Got, OptB) then begin case Length(Got)>=Length(OptB) of true : begin FB := '' ; CRD := Copy(Got, Succ(Length(OptB)), 255) end ; false : begin CRD := '' ; FB := Copy(OptB, Succ(Length(Got)), 255) end ; end ; Write(' ?? PartMatch : being tried') ; Um ; EXIT end ; Write(' ?? MisMatch : cannot be handled') ; Um ; EXIT ; end {Bas} ; if So in [Src, Dst] then with Root^ do begin PL := Items[So] ; New(Items[So]) ; with Items[So]^ do begin Next := PL ; No := LNo ; if So=Src then repeat Q := Pos('%', Got) ; if Q=0 then BREAK ; Got[Q] := char(Hex(Got[Q+1])*16+Hex(Got[Q+2])) ; Delete(Got, Q+1, 2) until false ; { if So=Src then for Q := 1 to Length(Got) do if Got[Q]='/' then Got[Q] := Slant ; } if (So=Dst) and (Length(Got)>AncLen) then Got[0] := char(AncLen) ; GetMem(Pstr, Succ(Length(FB)+Length(Got))) ; Pstr^ := FB+Got ; end {Items[So]^} ; Inc(ACount[So]) end {Root^} ; end {ExamineInLtGt} ; procedure Ingest(var F : file ; const DN : S80 ; var FB, CRD : S80 ; const Root : PFileList) ; const CommTest : string [3] = '!--' ; BufMin = -8192 { -512 {-256} ; BufMax = 16383 { < MaxInt } ; var InBuf : array [BufMin..BufMax] of char ; PGot : Pstring ; Icom, LineNumber, LNo : word ; BufEnd, PosLT, PosGT, NewPos : integer ; C : char ; Find : (LT, GT, EC) ; begin LineNumber := 1 ; if Viz>More then Write(' Ingesting ') ; PosLT := 0 ; Find := LT ; repeat BlockRead(F, InBuf[0], BufMax+1, BufEnd) ; if BufEnd=0 then BREAK ; repeat if Find=LT then begin while PosLT too wide for buffer slide?') ; HALT end ; Move(InBuf[PosLT], InBuf[NewPos], BufEnd-PosLT) ; PosLT := NewPos ; PosGT := 0 ; BREAK { to BlockRead } end ; end {GT} ; if Find=GT then begin PGot := Addr(InBuf[PosLT]) ; NewPos := PosGT-PosLT-1 ; if NewPos>255 then NewPos := 255 ; PGot^[0] := Char(NewPos) ; if Length(PGot^) >= Length('A NAME=1') then ExamineInLtGt(PGot^, FB, CRD, Root, LNo) { content of < .. > } ; Find := LT ; PosLT := PosGT ; end {GT} ; if Find=EC then begin while PosGTMore then Write(' Ingested ', LineNumber, ' lines ') ; Root^.Listed := true ; end {Ingest} ; const FLRoot : PFileList = NIL ; FileCount : word = 0 ; MaxFiles : word = $FFFF ; MaxDeep : word = $FFFF ; procedure ListUnusedNames ; var PFL : PFileList ; PN : PItem ; begin PFL := FLRoot ; while PFL<>NIL do begin PN := PFL^.Items[Dst] ; while PN<>NIL do begin if PN^.No<>0 then begin Inc(NotUsed) ; Write('@ ', PFL^.DosFiNa^, Space, PN^.No, ' "', PN^.Pstr^, '": unused NAME.') ; Umm(UnUsed=Ustop) ; end ; PN := PN^.Next end ; PFL := PFL^.Next end ; end {ListUnusedNames} ; function PrependToFileList(const DosFileName : string) : PFileList ; var PTemp : PFileList ; begin PTemp := FLRoot ; New(FLRoot) ; with FLRoot^ do begin Next := PTemp ; Items[Src] := NIL ; Items[Dst] := NIL ; GetMem(DosFiNa, Succ(Length(DosFileName))) ; DosFiNa^ := DosFileName ; Exists := false ; Listed := false end ; PrependToFileList := FLRoot end {PrependToFileList} ; var F : file { Each file is closed before another is attempted } ; SR : {$IFDEF DELPHI} TSearchRec {$ELSE} SearchRec {$ENDIF} ; procedure VerifyFile(const DosName, FB, CRD, HTMLname : S80 ; const PDst : PFileList ; const Deep : word) ; forward ; procedure ProcessName (var PdstFile : PFileList ; var FB, CRD, HTMLname, DosName : S80 ; const WhyP : string ; const Deep : word) ; {$IFDEF DELPHI} {} const AnyFile = faAnyFile ; VolumeID = faVolumeID ; {} var DosError : integer ; {$ENDIF} { type Bits = (RO, Hd, Sy, VI, D, A) ; ByteSet = set of Bits ; } var IOR : integer ; Extn : string [5] ; ReadIt, Diry, GoodDy, HTML : boolean ; B : byte ; begin if Viz>More then Write(' Prepend ') ; PdstFile := PrependToFileList(DosName) ; Diry := DosName[Length(DosName)]=Slant ; if Diry then Dec(DosName[0]) ; if Viz>More then Write(' FindFirst ') ; {$IFDEF DELPHI} DosError := {$ENDIF} FindFirst(DosName, AnyFile-VolumeID, SR) ; if DosError<>0 then begin if Diry then Inc(TestDirs[Nay]) else Inc(TestFiles[Nay]) ; WhyError(WhyP, 'FindFirst', DosError) ; EXIT end ; if Viz>More then Write('FF-OK ') ; B := SR.Attr { Attr is integer in D3 } ; GoodDy := Diry = ((B and $10)>0) ; {$UNDEF FC} {$IFDEF LFN} {$DEFINE FC} {$ENDIF} {$IFDEF DELPHI} {$DEFINE FC} {$ENDIF} {$IFDEF FC} FindClose(SR) ; {$ENDIF} case Diry of true: begin Inc(TestDirs[Perhaps(GoodDy)]) ; if GoodDy then PdstFile^.Exists := true else begin Write(WhyP, ' non-directory found') ; Um ; EXIT end ; if Viz>More then Writeln(' directory exists.') ; end ; false: begin if not GoodDy then begin Inc(TestFiles[Nay]) ; Write(WhyP, ' directory found') ; Um ; EXIT end ; if Viz>More then Write(' Opening ') ; Assign(F, DosName) ; {$I-} Reset(F, 1) ; {$I+} IOR := IOResult ; Inc(TestFiles[Perhaps(IOR=0)]) ; if IOR<>0 then begin if Viz>More then Writeln ; WhyError(WhyP, 'Open', IOR) end ; if IOR=0 then begin PdstFile^.Exists := true ; Extn := UpCaseStr(Copy(HTMLname, Length(HTMLname)-3, 4)) ; HTML := ((Extn='.HTM') or (Extn='HTML')) ; if not HTML then Inc(NotHTM) ; ReadIt := HTML and (DeepMore then Writeln(' Closed.') ; if ReadIt then begin VerifyFile(DosName, FB, CRD, HTMLname, PdstFile, Deep+1) ; end {ReadIt} ; end {IOR=0} ; end ; end {case} ; end {ProcessName} ; function TestName(FB, CRD, HTMLname : S80 ; const WhyT : string ; const Deep : word) : PFileList ; var PdstFile : PFileList ; NewDosName, OldDosName : S80 ; P : byte ; begin if Viz>Lots then begin OldDosName := CRD + HTMLname ; Writeln(^M^J' TestName "', OldDosName, '"') end ; if Pos('...', HTMLname)>0 then begin Write(WhyT, ' treble-dot') ; Um end ; if Copy(HTMLname, 1, 1) = Slant then begin Delete(HTMLname, 1, 1) ; CRD := '' end ; while Copy(HTMLname, 1, 3) = '..'+Slant do if CRD>'' then begin Delete(HTMLname, 1, 3) ; repeat Dec(CRD[0]) until (Length(CRD)=0) or (CRD[Length(CRD)]=Slant) ; end else BREAK ; (* repeat B := Pos('.'+Slant, HTMLname) ; if B=0 then BREAK ; if Viz>More then Writeln('!! ', HTMLName) ; Delete(HTMLname, B, 2) until false ; *) repeat P := Pos(Slant, HTMLname) ; if P=0 then BREAK ; CRD := CRD+Copy(HTMLname, 1, P) ; Delete(HTMLname, 1, P) ; until false ; NewDosName := CRD + HTMLname ; PdstFile := FLRoot ; while PdstFile<>NIL do begin if PdstFile^.DosFiNa^ = NewDosName then BREAK ; PdstFile := PdstFile^.Next end ; if PdstFile<>NIL then begin if not PdstFile^.Exists then begin Write(WhyT, ' already not found') ; Umm(Again=AStop) end else if Viz>More then Writeln(' file known.') ; TestName := PdstFile ; EXIT end ; if Viz>More then Write(^M^J' TestName "', NewDosName, '" ') ; if NewDosName>'' then ProcessName(PdstFile, FB, CRD, HTMLname, NewDosName, WhyT, Deep) ; TestName := PdstFile ; if Viz>Lots then Writeln(' TestName "', OldDosName, '" done.') ; end {TestName} ; var BatF : text ; const BatCmd : S80 = 'Test' ; BatNam : S80 = 'NUL' ; procedure VerifyFile(const DosName, FB, CRD, HTMLname : S80 ; const PDst : PFileList ; const Deep : word) ; var PdstFile : PFileList ; PsrcItem, PdstItem, PT, PX : PItem ; PWhy, Want : PString ; WebNam : S80 ; Anchor : string [AncLen] ; B : byte ; begin New(PWhy) ; if Viz>More then Writeln(' VerifyFile "', DosName, '" :-') ; Inc(FileCount) ; if Viz in [Less, Norm] then Writeln(' LinkSeek', FileCount:4, ',', Deep:4, '; ', {$IFDEF R} {$IFDEF BORPAS} Sptr, Space, {$ENDIF} MemAvail, '; ', {$ENDIF} DosName) ; Writeln(BatF, BatCmd, Spc, DosName) ; {Make reversed list :} PX := PDst^.Items[Dst] ; PdstItem := NIL ; while PX<>NIL do begin PT := PX^.Next ; PX^.Next := PdstItem ; PdstItem := PX ; PX := PT end ; PDst^.Items[Dst] := PdstItem ; {Duplicate name check :} PX := PdstItem ; while PX<>NIL do begin PT := PX^.Next ; while PT<>NIL do begin if PT^.PStr^=PX^.PStr^ then begin Write(ErrLoc(DosName, PX^.No), ' ', PT^.No, ' "', PX^.PStr^, '" repeated') ; Inc(Dupes) ; Um ; BREAK end ; PT := PT^.Next end ; PX := PX^.Next end ; {Make reversed list :} PX := PDst^.Items[Src] ; PsrcItem := NIL ; while PX<>NIL do begin PT := PX^.Next ; PX^.Next := PsrcItem ; PsrcItem := PX ; PX := PT end ; while PsrcItem<>NIL do begin with PsrcItem^ do begin Want := PStr ; B := Pos('#', Want^) ; if B=0 then B := 254 ; WebNam := Copy(Want^, 1, Pred(B)) ; Anchor := Copy(Want^, Succ(B), 255) ; PWhy^ := ErrLoc(DosName, No) + ' "'+Want^+'":' ; if Viz>More then Write(Space, PWhy^) ; if WebNam='' then PdstFile := PDst else PdstFile := TestName(FB, CRD, WebNam, PWhy^, Deep) ; if Anchor<>'' then with PdstFile^ do if Exists then case Listed of true : begin if Viz>More then Write(^M^J' Seek "', Anchor, '" in "', DosFiNa^ , '" ') ; PdstItem := Items[Dst] ; while PdstItem<>NIL do begin if PdstItem^.Pstr^=Anchor then BREAK ; PdstItem := PdstItem^.Next end {PdstItem} ; Inc(TestAnkas[Perhaps(PdstItem<>NIL)]) ; if PdstItem<>NIL then PdstItem^.No := 0 ; (***) if PdstItem<>NIL then begin if Viz>More then Writeln(' OK.') end else begin if Viz>More then Writeln ; Write(PWhy^, ' NAME not found') ; Um ; end {NIL} ; end {Listed} ; false : begin if Viz>More then Writeln ; Inc(TestAnkas[Dunno]) end {not Listed} ; end {case} ; end {PsrcItem^} ; PT := PSrcItem ; PsrcItem := PsrcItem^.Next ; with PT^ do FreeMem(Pstr, Succ(Length(Pstr^))) ; Dispose(PT) ; end {PsrcItem<>NIL} ; if Viz>More then Writeln(' VerifyFile "', DosName, '" done; file ', FileCount, '.') ; Dispose(PWhy) end {VerifyFile} ; {$IFDEF SLASH} procedure NewProcess(FLPtr : PFileList) ; var FB, CRD : S80 ; begin FB := '' ; CRD := '' ; Writeln('NewProcess "', FLPtr^.DosFiNa^, '"') ; { ProcessName(FLPtr, FB, CRD, FLPtr^.DosFiNa^, FLPtr^.DosFiNa^, Why, Deep) ; { ... } end {NewProcess} ; procedure NewJob(const Param : string) ; var FLPtr : PFileList ; begin Writeln('NEWJOB BEGIN') ; { Create list entry for given file "Param" } New(FLRoot) ; with FLRoot^ do begin Next := NIL ; DosFiNa := Addr(Param) ; Items[Src] := NIL ; Items [Dst] := NIL ; Exists := false {?} ; Listed := false ; end ; { Scan list ; NewProcess generally extends it } FLPtr := FLRoot ; repeat NewProcess(FLPtr) ; FLPtr := FLPtr^.Next until FLPtr = NIL ; Writeln('NEWJOB END') end {NewJob} ; {$ENDIF SLASH} procedure ReportCounts(const S : string ; const A : APoI) ; begin Write(' Relative citations: ', S:12, ' - missing ', A[Nay], ', found ', A[Yes]) ; if A[Dunno]>0 then Write(', untested ', A[Dunno]) ; Writeln(' ;') end {ReportCounts} ; function QStr(const B : boolean ; N : word) : string ; var S : string [5] ; begin S := '?' ; if B then Str(N, S) ; QStr := S end {QStr} ; procedure Help ; begin Writeln('CHEKLINX.PAS www.merlyn.demon.co.uk >= ', Today, ^M^J' Compiled with ', {$IFDEF BORPAS} 'Borland ', {$ELSE} {} 'Unknown ', {$ENDIF} {$IFDEF DELPHI} 'Delphi. ', {$ENDIF} {$IFDEF PASCAL} 'Pascal ', {} {$IFDEF MSDOS} 'MSDOS', {$ELSE} {} {$IFDEF DPMI} 'DPMI', {$ELSE} {} 'Unknown', {$ENDIF} {$ENDIF} ' mode. ', {$ENDIF} {$IFDEF BORPAS} {$IFNDEF LFN} 'No ', {$ENDIF} {$ENDIF} 'LFN. ', '/H for Help.') ; Writeln('CHEKLINX [options] RootFile ...') ; Writeln(' opts:', ^I'/: wait on local refs'^I^I'/Bbase - HREF= of current directory'^M^J, ^I'/Dn file seek depth'^I^I'/Fn file seek count'^M^J, ^I'/Jbatcmd - default "test"'^I'/Kbatfil - filenames file - X.BAT'^M^J, ^I'/Cn, /Ln, /Qn, /Un - n = 0,1,2 = Miss, Show, Stop for:'^M^J, ^I^I'UpperCase, file component >8.3, unquoted link, unused NAME'^M^J, ^I'/P look in ', ^I^I'/Vn volubility (', byte(Zero), '..', byte(Full), ')'^M^J, ' For more, now see in cheklinx.txt.' ) ; HALT end ; procedure DoAFilePara(const Para : string) ; begin if Viz>Zero then Writeln('Doing ', Para) ; Assign(BatF, BatNam) ; Rewrite(BatF) ; case WidthSearch of false : if not TestName('', '', Para, '', 0)^.Exists then begin Writeln('** Some error "', Para, '".') ; Help end ; true : {$IFDEF SLASH} NewJob(Para) {$ENDIF} ; end {case WidthSearch} ; Close(BatF) ; if UnUsed>Umiss then ListUnusedNames ; end {DoAFilePara} ; procedure ProcessParameters ; var J, N : integer ; Para : S80 ; {} procedure Ow ; {} begin Writeln('** Parameter error "', Para, '".') ; Help end {Ow} ; begin for J := 1 to ParamCount do begin Para := ParamStr(J) ; if Pos(Para, '/? -? /h -h /H -H')>0 then Help ; case Para[1] of '/' : if Length(Para)<2 then Ow else case UpCase(Para[2]) of ':' : Colon := true ; 'A' : begin Val(Copy(Para, 3, 255), byte(Again), N) ; if N<>0 then Ow ; end ; 'B' : OptB := Copy(Para, 3, 255) ; 'C' : begin Val(Copy(Para, 3, 255), byte(UCWarn), N) ; if N<>0 then Ow ; end ; 'D' : begin Val(Copy(Para, 3, 255), MaxDeep, N) ; if N<>0 then Ow ; end ; 'F' : begin Val(Copy(Para, 3, 255), MaxFiles, N) ; if N<>0 then Ow ; end ; 'J' : BatNam := Copy(Para, 3, 255) ; 'K' : BatCmd := Copy(Para, 3, 255) ; 'L' : begin Val(Copy(Para, 3, 255), byte(LongWarn), N) ; if N<>0 then Ow ; end ; 'P' : ParamTest := true ; 'Q' : begin Val(Copy(Para, 3, 255), byte(QuoTest), N) ; if N<>0 then Ow ; end ; 'V' : begin Val(Copy(Para, 3, 255), byte(Viz), N) ; if N<>0 then Ow ; end ; 'U' : begin Val(Copy(Para, 3, 255), byte(UnUsed), N) ; if N<>0 then Ow ; end ; {$IFDEF SLASH} '/' : WidthSearch := true ; {$ENDIF} { use // param } else Ow end {case P2}; '\' : begin Write('** File not relative: ') ; Ow end ; else begin DoAFilePara(Para) ; if J1], ' tested ;', ACount[Dst]:6, ' anchors seen ;', ACount[Src]:6, ' relative cites seen ;') ; ReportCounts('directories', TestDirs) ; ReportCounts('filenames', TestFiles) ; ReportCounts('anchors', TestAnkas) ; Writeln(' Local URLs ', LocalURLs, ' ; Odd A-refs ', OddArefs, ' ; Make relatives ', Relables, ' ; NotHTM ', NotHTM, ' ;') ; Writeln( ' Links over 8.3 format ', QStr(LongWarn>Lmiss, Not8_3), ' ;', ' Links with Upper Case ', QStr(UCWarn>Cmiss, UCChars), ' ; Links with "\" ', BSlash, ' ;') ; Writeln(' Repeated NAMEs ', Dupes, ' ; Unused NAMEs ', QStr(UnUsed>Umiss, NotUsed), ' ; UnQuoted HREF/NAME/&c. ', QStr(QuoTest>QMiss, NoQuos), ' ;') ; Writeln(' Empty values ', Empty, ' ; Far URLs ', FarURLs, ' ;') ; end {DoReport} ; BEGIN ; {$IFDEF HEAPLIMIT (needs BP7 DPMI)} HeapLimit := 1 ; {$ENDIF} FileMode := 0 ; ProcessParameters ; if FileCount=0 then DoAFilePara('index.htm') ; if FileCount>0 then DoReport ; if Viz>Zero then Writeln('CHEKLINX Done.') ; { Um ; } END.