
{$IFNDEF __TMT__} {$M $8000, 0, 0} {$ENDIF}

program HUNT {needs stack and no heap} {$R+,S+}
  {$IFDEF VER40} NEEDS TurboPascal 5.0+ {$ENDIF} ;

{ This program is used at your own risk; RSVP. }

{ Beginnings of output lines are chosen for | SORT }

{ HUNT scans directories, subdirectories, and allows commands on its findings.
  Any effects of DOS's APPEND ASSIGN JOIN SUBST have not been considered.
  With no parameters, '*.*' is used, else '.*' or '*.*' is appended as needed.
  The first parameter defines a set of files to list, cf DIR, incl wildcards.
  Subsequent parameters - '-' or '/' is ignored if starting a parameter and
  case is ignored - may include one or two strings, S1 S2, each bounded by '"';
  if so, for each file found the string 'S1 <filename.ext> S2' is offered
  for COMMAND.COM (Unconditionally if any parameter starts 'U') [if "S1"="",
  MSDOS will (ignoring <.ext>) try to execute '<filename>.COM/EXE/BAT S2']
  (if 'S1...S2' changes the list of files, caution!); 'T' means '"TYPE"';
  at offer, reply with first character of: Yes (to do), No (to not do),
  Unconditionally (to do all the rest), Quit (to offer no more) or Skip
  (to skip the rest of the files in this directory).  HUNT /? gives HELP.
  Others -
  A = filename first (for Alphabetical |SORT)
  B = Before/= date-time - as B89/11/27-19:55:46 or B#19:55:46 - can truncate
  C = offer subdirectory containing file/dir found; if yes, ChDir & exit
  D = Directories only are to be found
  F = From date-time - as F89/11/27-19:55:02 or F#19:55:02 - can truncate
  I$ = Ibid - insert $+directory where file found just before string S2
  J$ = Jbid - insert $+directory where file found just after string S2
  L = scan subdirs Later than files, rather than before files
  N = New (current date) files only
  O = Only put filenames on Standard Output (new 29+/11/90)
  P = put Path from CD at end of line (if no ") - useful with S|sort
  Q = Quieter - omit * lines
  R = Rootwards directories also, no PATH search
  S = Subdirectory contents also, no PATH search
  T = "TYPE"
  U = Unconditionally
  X = COM, EXE, BAT extensions; with P, searches PATH using GetEnv
  Y = from Yesterday (F#-1)
  ~*~ = character * replaces " above henceforth in line
  + = put no space after S1 or before S2 (changed 26/01/90)
  2,4 = force 2 or 4 digit years (from 1998/01/02)
  *, \ are ignored (& can thus default for first parameter in *.BAT)

  HUNT FRED x p should show all files FRED might now execute, in order;
  HUNT \ x s should show all executable files.  HUNT mostly uses Std_Out.
  It can be useful to pipe the output through FIND "/" &/or SLOW &/or SHOWER.
  Try HUNT * s p q "fc" id: "*.*"
  Other operations can be done by invoking a suitable ad hoc batch file
  ú (e.g. HUNT * S "compare c: d:" where DIFF.BAT contains FC %1%3 %2%3).
  Now reorganised to pipe better with ".." & queries.  HUNT /? also helps.
  Consider B:?\?>HUNT * "hunt a:" + " s ~#~ #copy# #b:#"
  ú & B:?\?>HUNT HUNT.* ~'~ 'FIND /I "find"' u !
  Viral infection &c test : a ? precedes names containing sinful characters :
  ú try ?:?\?>HUNT \ s p q | find "?"
  With B & F, if the next char is "#", it represents TODAY, next is time;
  ú if "-" follows "#", the "days-before" number follows, followed by time;
  ú the default epoch fields represent 2000/00/00-00:00:00.  No <1980 check!
  1994/09/14 : Keyboard response was Readln(Para), is Para := ReadKey
  1994/09/29 : if later in line, N supersedes F|B and vice versa
  1995/02/02 : after F|B, today is # (was =)
  Note : within actual "..", > >> < | are preserved for the S1 command.
  1996/07/08 : OK with (does not show) W95 long file name entries.
  1997/12/15 : made Year 2044 compliant.
  1998/01/04 : Options 2 & 4 - force #YearDigits.
  1998/02/03 : Crt removed, ReadChar replaces ReadKey.
  1998/07/20 : Option D- - no directories shown.
  1999/01/24 : Option C changed ?  if D, change to dir found.
  1999/03/20 : "?" repositioned for Option A; <Bee4 now <=Bee4.
  1999/04/24 : Option f## (& b##). }


uses Dos ;

function V(X : longint) : longint { for Year2044 compliance } ;
begin V := X xor $80000000 end {V} ;

function ReadChar : char { in lieu of Crt.ReadKey, for normal keys } ;
var R : registers ;
begin
  with R do begin AH := 0 ; Intr($16, R) ; ReadChar := char(AL) end ;
  end {ReadChar} ;

{$I+}
procedure Quit(Sq : string) ; var C : char ; const W : word = 9 ;
begin
  Writeln('HUNT: ', Sq, '; quit.'^G) ;
  Write('Try to use most of O/P so far? ERRORLEVEL digit=(0=Yes, >0=No) ? ') ;
  C := ReadChar ; Writeln(C) ; if C>='0' then W := Ord(C) -  Ord('0') ;
  Writeln('ERRORLEVEL=', W) ; Halt(W) end {Quit} ;
{$I-}

procedure IOerr(ErrS : string ; IOR : integer) ; var IORS : string [5] ;
begin Str(IOR, IORS) ; Quit(ErrS+' IOResult '+IORS) end {IOerr} ;

procedure IOCheck(Fail : string) ; var IOR : integer ;
begin IOR := IOResult ; if IOR>0 then IOerr(Fail, IOR) end {IOCheck} ;

procedure IO ; var IOR : integer ;
begin IOR := IOResult ; if IOR>0 then IOerr('IO:', IOR) end {IO} ;


const Sp = char(32) ;

function CC(J : word) : string { CC:=00..09,10..9999 } ; var St : string [4] ;
begin Str(J:2, St) ; if St[1]=Sp then St[1] := '0' ; CC := St end ;

var DT : DateTime ;

procedure DoDate ;
begin with DT do Write(Sp, CC(Year), '/', CC(Month), '/', CC(Day),
    '-', CC(Hour), ':', CC(Min), ':', CC(Sec)) end {DoDate} ;


const
MinT = $00000000 ; MaxT = $FFFFFFFF ;
Atst = 'rhsvdaè#' ; W95LFN = $0F {rhsv} ;
MaxAtt = Length(Atst) ; Atts : string [MaxAtt] = Atst ;

const { initialised variables }
Dogs : char = {$IFDEF __TMT__} '''' {$ELSE} '"' {$ENDIF}
  { TP/BP Default '"', changes for special cases, see ~ } ;
Nbad : word = 0 { No. of Bad names } ;
NofF : word = 0 { No. of Files } ;
NofB : longint = 0 { No. of Bytes } ;
ceb : string [5] = '' ;
Pth : string [5] = '' ;
Dr : string [4] = '' ;
SbD : string [5] = '' ;
SpD : string [5] = '' ;
Nu : string [4] = '' ;
IJst : string [40] = '' ;
Alph : boolean = false ;
Ibid : boolean = false ;
Jbid : boolean = false ;
SubDir : boolean = false ;
DirOnly : boolean = false ;
NoDirys : boolean = false ;
NewF : boolean = false ;
ComExeBat : boolean = false ;
Skip : boolean = false ;
Job : boolean = false ;
Path : boolean = false ;
Quy : boolean = true ;
Qot : boolean = false ;
Cdno : byte = 0 ;
Cmnd : array [1..2] of string [80] = ('TYPE', '') ;
From : longint = MinT { longword when } ;
Bee4 : longint = MaxT { " " } ;
S12S : string [1] = Sp ;
ChD : boolean = false ;
Show : boolean = true ;
Super : boolean = false ;
Only : boolean = false ;
Lata : boolean = false ;
DS : DirStr = '' ;
NS : NameStr = '' ;
ES : ExtStr = '' ;
YrNo : char = '?' ;


procedure Explain(var Scr : Text) ;
{$IFDEF BULLER} var QQ : text ; J : byte ; Source : string ; {$ENDIF}
begin Skip := true ;
  Writeln(Scr, ' * \ Alpha Before ChDir DirOnly- ',
    'From Ibid Jbid Later New Only Path Quiet') ;
  Writeln(Scr, ' Rootwards SubDir Type Uncond eXecutable Yesterday ',
    Dogs, 'cmnd', Dogs, 's ~*~ + 2/4 ?') ;
  Writeln(Scr, ' (for more info, see start of HUNT.PAS)') ;
  {$IFDEF BULLER}
  Source := FExpand(ParamStr(0)) ; Dec(Source[0], 3) ;
  Assign(QQ, Source+'Pas') ; Reset(QQ) ;
  for J := 1 to 44 do begin
    Readln(QQ, Source) ; if J>22 then Writeln(Scr, Source) end ;
  {$ENDIF}
  end {Explain} ;


var NoEA : array [1..MaxAtt] of word { Number Of Each Attribute } ;

var JH, JM, JS, IY, IM, ID, IW : word ;


type UpDn = (Up, Dn) ;



procedure DoADir(Prfx : string ; UD : UpDn ; Miss : string) ;

function Action(var DirInf : SearchRec) : boolean ;
const Pset = ['Y', 'N', 'U', 'Q', 'S'] ;
var Jndx : byte ;
ParS : string ;
ESiz : word ;
Est : string [6] ;
Para : char ;
begin with DirInf do begin Para := #0 ; Action := true ;

    {$I+}

    if Ibid then ParS := Prfx else ParS := '' ;
    ParS := Cmnd[1] + S12S +Prfx+Name + S12S +IJst +ParS+Cmnd[2] ;
    if Jbid then ParS := ParS+S12S+Prfx ;
    Write(ParS:63, Sp) ;
    if Quy then begin Write('(y/n/U/Q/S) ? '^G) ;
      repeat Para := UpCase(ReadChar) until Para in Pset ;
      end else Para := 'Y' ;
    Writeln(Para) ;
    if Para='S' then EXIT ;
    if Para='Q' then begin Job := false ; ChD := false end ;
    if Para='U' then begin Quy := false ; Para := 'Y' end ;
    if Para='Y' then begin
      if ChD then begin

        if DirOnly then Prfx := Prfx+Name else
          Delete(Prfx, Length(Prfx), 1) ;


        ChDir(Prfx) ; HALT end ;

      Esiz := 50 + EnvCount+1 {0s} ;
      for Jndx := 1 to EnvCount do Inc(Esiz, Length(EnvStr(Jndx))) ;
      if Esiz<160 then Esiz := 160 ; Str(Esiz, Est) ;

      Flush(Output) ;
      SwapVectors ;
      Exec(GetEnv('COMSPEC'), '/E:'+Est+' /C '+ParS) ;
      (*** COMMAND.COM /C loses error returns ***)
      SwapVectors ;
      if (DosError<>0) or (DosExitCode<>0) then begin
        Writeln('COMSPEC DosError ':45, DosError,
          '  DosExitCode '^G, DosExitCode) { NOT ParStr's } ;
        Skip := true end ;
      end {Y} ;

    {$I-}

    Action := false end end {Action} ;

function PfxS : string ;
begin if Prfx='' then PfxS := '.\' else PfxS := Prfx end {PfxS} ;

var NofBS, NofFS, NbadS : longint ;

function ProcessIt(var DirInf : SearchRec) : boolean ;
const
GoodSet =
  ['!', '#'..')', '-', '.', '0'..'9', '@'..'Z', '^'..'`', '{', '}', '~'] ;
var
Atrb : string [MaxAtt] ;
Indx, Jatt : byte ;
Deed : boolean ;
Flag : char ;
NuNa : string [12] ;

begin with DirInf, DT do begin
    Flag := Sp ; Atrb := Atts ;
    { 1:6 - ReadOnly Hidden SysFile VolumeID Directory Archive }
    { 7:8 - ?undef? Shareable? }
    for JAtt := 1 to MaxAtt do
      if (Attr and (1 shl (JAtt-1)))=0 then Atrb[JAtt] := '.'
      else Inc(NoEA[JAtt]) ;
    if ((Atrb[5]='.') xor DirOnly) then begin                  { NoDirys? }
      Inc(NofB, Size) ; Inc(NofF) ;
      Inc(NofBS, Size) ; Inc(NofFS) end ;
    if (Month=0) or (Month>12) or (Day=0)
      or (Hour>23) or (Min>59) or (Sec>59) then Flag := '?' ;
    for Indx := 1 to Length(Name) do
      if not (Name[Indx] in GoodSet) then Flag := '?' ;
    if Flag<>Sp then begin Inc(Nbad) ; Inc(NbadS) end ;
    if Pos('.', Name)=0 then Name := Name+'.' ;
    NuNa := Name ;
    for Indx := Pos('.', NuNa) to 8 do Insert(Sp, NuNa, Indx) ;
    while Length(NuNa)<12 do NuNa := NuNa+Sp ;

    if YrNo<>'4' then
      if (YrNo='2') or ((IY<2000) and (Year<2000)) then
      Year := Year mod 100 ;

    if Only then Write(Prfx, Name)
      else begin
      if not Alph then DoDate ;
      Write(Sp, NuNa, Flag) ;
      if Atrb[5]='.' then Write(Size:9) else Write('':9) ;
      Write(Sp, Atrb) ;
      if Alph then DoDate ;
      if Flag<>Sp then Write(^G) ;
      end {not Only} ;

    Deed := (Job or ChD) and ( (Atrb[5]='.') xor DirOnly )       { NoDirys? }
      and (Atrb[2]='.') and (Atrb[3]='.') ;

    if (not Deed) and Path then Write(' via ', PfxS) ;

    Writeln ; IO ;

    ProcessIt := false ;
    if Deed then ProcessIt := Action(DirInf) ;

    end end {ProcessIt} ;


function DoOneFile(var DirInf : SearchRec) : boolean ;
begin DoOneFile := false ;
  with DirInf do
    { if Attr=W95LFN then begin Writeln('+ W95lfn') ; IO end else }
    if (V(Time) >= V(From)) and (V(Time) <= V(Bee4)) then begin
    UnPackTime(Time, DT) ;
    with DT do if ((not NewF) or ((Year=IY) and (Month=IM) and (Day=ID)))

      and ((not DirOnly) or boolean(Attr and Directory))
      and ((not NoDirys) or not boolean(Attr and Directory))

      and not ( (Name='.') or (Name='..') )
      then DoOneFile := ProcessIt(DirInf) ;
    end {Time OK} ;
  end {DoOneFile} ;



procedure DoFiles ;
const Exts : array [0..3] of string [3] = ('', 'BAT', 'EXE', 'COM') ;
var DirInfo : SearchRec ; Ex : shortint ;
begin NofBS := 0 ; NbadS := 0 ; NofFS := 0 ;

  if ComExeBat and (ES='.') then Ex := 3 else Ex := 0 ;

  repeat FindFirst(Prfx+NS+ES+Exts[Ex], AnyFile-VolumeID, DirInfo) ;

    if (DosError<>18) and (DosError<>0) then begin
      {$I+}
      Write('  *** FindFirst(', Prfx+NS+ES+Exts[Ex],
        ',,) -> DosError ', DosError, '; '^G) ;
      case DosError of
        3: Write('Path not found') ;
        151: Write('Unknown Unit') ;
        152: Write('Drive not ready') ;
        154: Write('CRC error in data') ;
        162: Write('Hardware Failure (density?)') ;
        else Write('See TP5.0 Ref Guide p.467-472.') ;
        end {case} ;
      Writeln ; Skip := true ; EXIT end ;
    {$I-}

    while DosError=0 do begin
      if DoOneFile(DirInfo) then EXIT ;
      FindNext(DirInfo) ;
      end {while 0} ;

    Dec(Ex) until Ex<1 ;
  end {DoFiles} ;


function DoSubDirs : word ;
var NSD : word ; DirInfoo : SearchRec ;
begin NSD := 0 ;
  if SubDir then begin {QV MS-DOS Bible Ed2 p.458 4Eh 4Fh}
    if Show then begin Writeln('  * scanning SubDirs of ', PfxS) ; IO end ;
    FindFirst(Prfx+'*.*', {Directory} AnyFile, DirInfoo) ;
    while DosError=0 do begin
      with DirInfoo do
        if boolean(Attr and Directory) and not ( (Name='.') or (Name='..') )
        then begin
        if Miss<>FExpand(Prfx+Name)+'\'
          then DoADir(Prfx+Name+'\', Dn, '')
          else if Show then begin
          Writeln('  ** Did ', Prfx+Name, '\ before') ; IO end ;
        Inc(NSD) end ;
      FindNext(DirInfoo) ;
      end {while 0} ;
    end {SubDir} ;
  DoSubDirs := NSD end {DoSubDirs} ;

var ShoNuDir, GoUpADir : boolean ;
var NofSD : word ;

begin {DoADir}

  if not Lata then NofSD := DoSubDirs { keep here } ;

  GoUpADir := Super and (UD=Up) and (FExpand(Prfx)<>FExpand(Prfx+'..\')) ;
  ShoNuDir := Show and (GoUpADir or Subdir) ;
  if ShoNuDir then begin Writeln('  * scanning in ', PfxS) ; IO end ;

  DoFiles ;

  if GoUpADir then begin
    if Show then begin Writeln('  * scanning up from ', PfxS) ; IO end ;
    DoADir(Prfx+'..\', Up, FExpand(Prfx)) end ;

  if Lata then NofSD := DoSubDirs { where ? } ;

  if ShoNuDir then begin
    Write('  ** in ', PfxS, ' : ', NofSD, ' SubDirs; ', NofFS, ' matches') ;
    if NbadS>0 then Write(', ', NbadS, ' badnames'^G) ;
    if not DirOnly then Write(', ', NofBS, ' bytes.') ;        { NoDirys? }
    Writeln ; IO end ;

  end { DoADir } ;




procedure PathScan ;
var ParStr, List : string ; Temp : PathStr ; Jn : byte ;
begin
  if Show then begin
    Writeln('  ** Now search rest of PATH **') ; IO end ;
  List := GetEnv('PATH') ;
  if Length(List)=255 then
    {$I+} Writeln('WARNING long path truncated ?'^G) {$I-}
    else if List[Length(List)]<>';' then List := List+';' ;
  GetDir(0, Temp) ;
  if Temp[Length(Temp)]<>'\' then Temp := Temp+'\' ;
  while Pos(';', List)>0 do begin
    Jn := Pos(';', List) ;
    ParStr := Copy(List, 1, Jn-1) ; Delete(List, 1, Jn) ;
    if ParStr[Length(ParStr)]<>'\' then ParStr := ParStr+'\' ;
    if ParStr<>Temp then DoADir(ParStr, Dn, '')
      else if Show then begin
      Writeln('  (* CURRENT ', ParStr, ' *)') ; IO end ;
    end {while} ;
  end {PathScan} ;


procedure GetLbl(Dev : char) ;
var DirInfo : SearchRec ; B, Ix : byte ;
begin FindFirst(Dev+':\*.*', VolumeID, DirInfo) ;
  with DirInfo do begin
    while DosError=0 do begin
      if Attr<>W95LFN then begin
        UnPackTime(Time, DT) ; B := Pos('.', Name) ;
        if B>0 then begin for Ix := B to 8 do Insert(Sp, Name, Ix) ;
          Delete(Name, 9, 1) end ;
        Write('   Label ', Dev, ': = ', Name) ; DoDate ;
        end ;
      FindNext(DirInfo) ;
      end ;
    end ;
  end {GetLbl} ;


var ParStr : string ;


function Fnq : word ; var F : word ;
begin F := 0 ;  Delete(ParStr, 1, 1) ;
  while (Length(ParStr)>0) and (ParStr[1] in ['0'..'9']) do begin
    F := 10*F + word(ParStr[1])-word('0') ; Delete(ParStr, 1, 1) end ;
  Fnq := F end {Fnq} ;


procedure GetDT(var X : longint) ;
const Ult : array [1..12] of byte = (31,28,31,30,31,30,31,31,30,31,30,31) ;
var JW : word ;
begin Write(Sp, ParStr[1]) ;
  with DT do begin
    if (Length(ParStr)>=2) and (ParStr[2]='#') then begin
      Delete(ParStr, 2, 1) ;
      Year := IY ; Month := IM ; Day := ID ;
      if (Length(ParStr)>=2) and (ParStr[2]='-') then begin
        Delete(ParStr, 2, 1) ;
        for JW := Fnq downto 1 do begin Dec(Day) ;
          if Day=0 then begin Dec(Month) ;
            if Month=0 then begin Month := 12 ; Dec(Year) end ;
            if (Month=2) and
              ((Year and 3) = 0) and ((Year mod 100 > 0) or (Year mod 400 = 0))
              then Day := 29 else Day := Ult[Month] ;
            end {Day 0};
          end {for} ;
        end {-} ;
      end {=}
    else begin Year := Fnq ; Month := Fnq ; Day := Fnq ;
      if Year<80 then Inc(Year, 100) ; if Year<1000 then Inc(Year, 1900) ;
      end ;
    if (Length(ParStr)>=2) and (ParStr[2]='#') then begin
      Hour := JH ; Min := JM ; Sec := JS end else begin
      Hour := Fnq ; Min := Fnq ; Sec := Fnq end ;
    end {with} ;
  DoDate ; Writeln ;
  PackTime(DT, X) ; NewF := false ; Nu := '' end {GetDT} ;


procedure ReadParams(var Scrn : Text) ;
var PN : word ;
begin
  {$I+}
  if ParamStr(1)='/?' then Explain(Scrn) else
    for PN := 2 to ParamCount do begin
    if Qot then ParStr := ParStr+Sp+ParamStr(PN) else begin
      ParStr := ParamStr(PN) ;
      if (Pos('-', ParStr)=1) or (Pos('/', ParStr)=1) then
        Delete(ParStr, 1, 1) ;
      case UpCase(ParStr[1]) of
        '*', '\' : ;
        '?' : Explain(Scrn) ;
        'A' : Alph := true ;
        'B' : GetDT(Bee4) ;
        'C' : begin ChD := true ; Cmnd[1] := 'GOTO' ; SubDir := true end ;
        'D' : if Copy(ParStr, 2, 1)<>'-' then
          begin DirOnly := true ; Dr := ' Dir' end else
          begin NoDirys := true ; Dr := ' NoD' end ;
        'F' : GetDT(From) ;
        'I' : begin Ibid := true ; IJst := Copy(ParStr, 2, 255) end ;
        'J' : begin Jbid := true ; IJst := Copy(ParStr, 2, 255) end ;
        'L' : Lata := true ;
        'N' : begin
          NewF := true ; Nu := ' New' ; From := MinT ; Bee4 := MaxT end ;
        'O' : begin Only := true ; Show := false end ;
        'P' : begin Path := true ; Pth := ' Path' end ;
        'Q' : Show := false ;
        'R' : begin Super := true ; SpD := ' SupD' end ;
        'S' : begin SubDir := true ; SbD := ' SubD' end ;
        'T' : begin Job := true ; Inc(Cdno) end ;
        'U' : Quy := false ;
        'X' : begin ComExeBat := true ; ceb := '(ceb)' end ;
        'Y' : begin ParStr := 'F#-1' ; GetDT(From) end ;
        '~' : if Copy(ParStr, 3, 1)='~' then Dogs := ParStr[2] ;
        '+' : S12S := '' ;
        '0'..'9' : YrNo := ParStr[1] ;
        else if ParStr[1]=Dogs then
          if (*? (Length(ParStr)>1) and ?*) (Cdno<2)
          then begin Job := true ; Qot := true ; ParStr[1] := ^M end
        else begin Skip := true ; Writeln(^G'Bad ', Dogs) end
        else begin Skip := true ;
          Writeln('Unrecognised parameter ', ParamStr(PN), '; quit.'^G) ;
          end {duff param.} ;
        end {case} ;
      end {Qot else} ;
    if (ParStr[Length(ParStr)]=Dogs) and not Skip then begin
      Qot := false ; Inc(Cdno) ;
      Cmnd[Cdno] := Copy(ParStr, 2, Length(ParStr)-2) end ;
    end {PN} ;

  if Qot then begin Skip := true ; Writeln(^G'Odd ', Dogs) end ;

  if ParamCount>0 then FSplit(ParamStr(1), DS, NS, ES) ;
  if NS='' then NS := '*' ;
  if ComExeBat and (ES='') then ES := '.' ; {!!!???!!!}
  if ES='' then ES := '.*' ;

  if ComExeBat and Path and (DS<>'') then begin
    Skip := true ; Writeln(DS, ^G'... x p is error') end ;

  if Skip then Halt(1) ;

  {$I-}
  end {ReadParams} ;


procedure Report ;
const
Mo : array [1..12] of string [3] =
  ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec') ;
Dy : array [0..6] of string [3] = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat') ;
var DirInfo : SearchRec ; Tmp, Tmpy : PathStr ; JA : byte ;
begin

  Write('Attribute counts - ') ;
  for JA := 1 to MaxAtt do if JA=4 then Write('':7) else
    Write(NoEA[JA]:5, Sp, Atts[JA]) ;
  Writeln ; IO ;

  GetTime(JH, JM, JS, IW) ; GetDate(IY, IM, ID, IW) ;
  Write('Date ', Dy[IW], Sp, ID, Sp, Mo[IM], IY:5, ',') ;
  Writeln(' time ', CC(JH), ':', CC(JM), ':', CC(JS), '.') ; IO ;

  Tmp := FExpand(DS+NS+ES) ; IW := word(Tmp[1])-word('@');
  Write('Disk bytes :', DiskSize(IW):10, '.') ;
  GetLbl(Tmp[1]) ; Writeln ; IO ;
  Write('Free bytes :', DiskFree(IW):10, '. ', NofF:7, ' matching ') ;
  if DirOnly then Write('dirs') else Write('files,', NofB:10, ' bytes') ;
  { NoDirys? }
  Writeln ; IO ;

  Tmpy := FExpand(DS) ; if Tmpy[Length(Tmpy)]='\' then Dec(Tmpy[0]) ;
  Write('Finding in : ') ;
  if Length(Tmpy)<=2 then Writeln('RootDir') else with DirInfo do begin
    FindFirst(Tmpy, {Directory} AnyFile, DirInfo) ;
    if DosError<>0 then Writeln(Tmpy, ' : DosError ', DosError) else begin
      Write(Name) ; UnPackTime(Time, DT) ; DoDate ; Writeln ; IO ;
      end end ;

  Writeln('Full names : ', Tmp, ceb, Nu, Dr, SpD, SbD, Pth) ; IO ;
  end {Report} ;



var Scrn : Text; BufOut : array [0..16383] of char ;


BEGIN ;
Assign(Scrn, 'CON') ; Rewrite(Scrn) ;
Writeln(Scrn, ^M'HUNT.PAS (q.v.) #8l >=2000-01-11 from ',
  FExpand(ParamStr(0)) {$IFDEF BULLER} , ' BULLERised' {$ENDIF}) ;

GetTime(JH, JM, JS, IW) ; GetDate(IY, IM, ID, IW) ;

ReadParams(Scrn) ;

FillChar(NoEA, SizeOf(NoEA), 0) ;

DoADir(DS, Up, '') ;

if ComExeBat and Path and not (Super or SubDir) then PathScan ;

if Job then begin Writeln ; IO end ;

if not Only then Report ;

Close(Output) ; IOCheck('Close(Output) problem') ;

if Nbad>0 then begin
  Writeln(Scrn, 'Bad character(s) or date/time in '^G, Nbad, ' name(s)'^G) ;
  IO end ;
Close(Scrn) ;
{ J R Stockton, jrs@merlyn.demon.co.uk.
  For documentation see comment herein. }
END.
