;   ViewDir 2.0/ size directory - Jim Butterfield.  April 5/90.
; Exec library calls
_LVOAllocMem          EQU -$C6
_LVOFreeMem           EQU -$D2
_LVOSetSignal         EQU -$132
_LVOCloseLibrary      EQU -$19E
_LVOOpenLibrary       EQU -$228
; DOS library calls
_LVOOpen              EQU -$1E
_LVOClose             EQU -$24
_LVORead              EQU -$2A
_LVOWrite             EQU -$30
_LVOOutput            EQU -$3C
_LVOLock              EQU -$54
_LVOUnLock            EQU -$5A
_LVOExamine           EQU -$66
_LVOExNext            EQU -$6C
_LVOCurrentDir        EQU -$7E
_LVOIoErr             EQU -$84
;
ACCESS_READ            equ -2
MODE_OLDFILE           equ 1005
INFOSIZE               equ 260
DATASIZE               equ 100
; FileInfoBlock items
fib_FileName           equ 8
fib_EntryType          equ 120
fib_Size               equ 124
fib_NumBlocks          equ 128
; IO Error Type
NO_MORE_ENTRIES        equ 232
;
;-- Initial setup:
;        offsets from A5
tSize    equ  -4
tCount   equ  -8
dosBase  equ  -12
argv     equ  -16
OutHandle equ -20
DataBlk  equ  -24
Blocker  equ  -25    ;byte
KillInf  equ  -26    ;byte
Look     equ  -27    ;byte
FileErr  equ  -28    ;byte
Level    equ  -30    ;word
String   equ  -42    ;12 bytes

       link   a5,#-44          ; common work area
       moveq  #0,d1
       move.l d1,FileErr(a5)  ; four bytes
trsp   move.b d1,-1(a0,d0)    ; c style string
       move.b -2(a0,d0),d1
       cmp.b  #$20,d1
       bne.s  lastCh
       subq.w #1,d0
       bra.s  trsp
lastCh sub.b  #$22,d1         ; kill trailing quote
       bne.s  spdump
       move.b d1,-2(a0,d0)
spdump move.b (a0)+,d0
       cmp.b  #$20,d0
       beq.s  spdump
       cmp.b  #$22,d0         ; leading quote
       beq.s  skipq
       cmp.b  #$2d,d0         ;dash
       beq.s  fgdump
       sub.b  #'?',d0
       beq.s  hook
       bra.s  spbak
fgdump move.b (a0)+,d0
       beq.s  hook
       and.b  #$5f,d0
       cmp.b  #$49,d0         ;-i
       bne.s  NotI
       move.b d0,KillInf(a5)
       bra.s  fgdump
NotI   cmp.b  #$54,d0
       bne.s  NotT
       move.b d0,Look(a5)
       bra.s  fgdump
NotT   cmp.b  #$42,d0        ;-b
       bne.s  spdump
       move.b d0,Blocker(a5)
       bra.s  fgdump
skipq  addq.l #1,a0
spbak  move.b -(a0),d0
       move.l a0,argv(a5)
;**  Level=0;  tCount=0;
hook   moveq  #0,d1
       move.l d1,Level(a5)
       move.l d1,tCount(a5)
; set up dos, output, here
       movem.l a0/a1/d0/d1,-(A7)
       move.b #1,FileErr(a5)
       lea    dosname(pc),a1    ; Name 'dos.library'.
       clr.l  d0                ;   Any version (0)
       move.l $4,a6             ;   Using Exec library
       jsr    _LVOOpenLibrary(a6)  ;   Open Dos library.
       move.l d0,dosBase(a5)    ; Remember DosBase ptr.
       beq    StartupQuit       ;      dos not opened
       move.l d0,a6             ; set Dos library
       jsr    _LVOOutput(a6)    ;   get CLI outhandle,
       move.l d0,OutHandle(a5)       ;   & then remember it.
       movem.l (a7)+,a0/a1/d0/d1
       tst.l  d0                ; no file name?
       beq.s  Prompt
;**    GetDir(argv[1]);
       move.l $4,a6             ; this calls for Exec
       moveq  #0,d1             ; any type of memory
       moveq  #DATASIZE,d0      ; size of block needed
       jsr    _LVOAllocMem(a6)  ; go get it
       move.l dosBase(a5),a6    ; restore Dos Library
       move.l d0,DataBlk(a5)    ; save the block address
       beq.s  DosQuit           ; quit if no memory
       move.l argv(a5),a0       ; file name
       bsr.s  GetDir
       move.l $4,a6             ; set Exec library
       move.l DataBlk(a5),a1    ; memory block address
       moveq  #DATASIZE,d0      ; size of block
       jsr    _LVOFreeMem(a6)   ; release this memory
DosQuit  move.l dosBase(a5),a6  ; set Dos Library
;**    switch (FileErr)
       subq.b #1,FileErr(a5)
       bne.s  Ncase1
;**      case 1:
;**        printf("Out of Memory\n");
       move.l OutHandle(a5),d1       ;file handle
       lea    NoMemMsg(pc),a1
       move.l a1,d2             ;outbuffer
       moveq  #NoMemLen,d3      ;length
       jsr    _LVOWrite(A6)

;**      case 2:
;**        printf("Can't find file.\n");
Ncase1 subq.b #1,FileErr(a5)
       bne.s  Ncase2
       move.l OutHandle(a5),d1       ;file handle
       lea    NoFileMsg(pc),a1
       move.l a1,d2             ;outbuffer
       moveq  #NoFileLen,d3     ;length
       jsr    _LVOWrite(A6)

;**      case 3:
;**        printf("^C\n");
Ncase2 subq.b #1,FileErr(a5)
       bne.s  endSwitch
       move.l OutHandle(a5),d1       ;file handle
       lea    CtrlCMsg(pc),a1
       move.l a1,d2
       moveq  #CtrlCLen,d3
       jsr    _LVOWrite(A6)
endSwitch   bra.s  LastGasp
;**      }
;**    }
;**  else printf("FORMAT:  ViewDir <DirectoryName>\n");
Prompt      move.l OutHandle(a5),d1
       lea    PromptMsg(pc),a1
       move.l a1,d2
       moveq  #PromptLen,d3
       jsr    _LVOWrite(A6)
;**  }
LastGasp:   move.l dosBase(a5),a1    ; DosBase to a1;
       move.l $4,a6             ;   then using Exec library,
       jsr    _LVOCloseLibrary(a6)    ;   close Dos library.
StartupQuit unlk   a5
       rts                      ; End of Program

;**void GetDir(char * Name)
;**  {
;**  unsigned long Size, Count, newLock, oldLock;
;**  struct FileInfoBlock *fibb;
;**  char *NameSave;
;            offsets from A4
Size        equ    -4
Count       equ    -8
newLock     equ    -12
oldLock     equ    -16
fibb        equ    -20
NameSave    equ    -24    ;drawer (calling) name
xName       equ    -28    ;name to be printed
fType       equ    -32    ;dir or file

GetDir link   A4,#-32
       move.l a0,xName(a4)
       move.l a0,NameSave(a4)
;**  Size = 0;
;**  Count =0;
;**  Count = 0;
       moveq  #0,d0
       move.l d0,Size(a4)
       move.l d0,Count(a4)
;**  FileErr =1;   /* signal Alloc error */
       move.b #1,FileErr(a5)
;**  if ((fibb = AllocMem(INFOSIZE,0)) != 0)
       move.l $4,a6             ; this calls for Exec
       moveq  #0,d1             ; any type of memory
       move.l #INFOSIZE,d0      ; size of block needed
       jsr    _LVOAllocMem(a6)  ; go get it
       move.l dosBase(a5),a6    ; restore Dos Library
       move.l d0,fibb(a4)       ; save the block address
       beq    GDExit            ; quit if no memory
;**    {
;**      FileErr =2;   /* signal file unreadable */
       move.b #2,FileErr(a5)
;**      if ((newLock = Lock(Name,ACCESS_READ)) != 0)
       move.l xName(a4),d1
       moveq  #ACCESS_READ,D2   ; get a read lock
       jsr    _LVOLock(a6)
       move.l d0,newLock(a4)    ; store the lock pointer
       beq    DropMem           ; couldn't get lock
;**      { if ((Examine(newLock,fibb)) != 0)
       move.l d0,d1             ; lock
       move.l fibb(a4),d2       ; file info block address
       jsr _LVOExamine(a6)      ; go for the data
;   Assume Examine never fails.  Go for the data.
;**        {
;**        FileErr =0;    /* got file, normal error sequence */
       move.b #0,FileErr(a5)
;**         {
;**              if (fibb->fib_EntryType < 0)
       move.l fibb(a4),a3
       move.l fib_EntryType(a3),d0
       move.l d0,fType(a4)
       bpl.s  TypeDir2
;**                {
;**                Size = fibb->fib_Size;
;**                Blox = fibb->fib_NumBlocks;
;**                Count = 1;
;**                }  /* file */
       move.l NameSave(a4),a0
       jsr    FilBit
       bra    NextItem
;**              else
TypeDir2:
;**           {
;**                oldLock = CurrentDir(newLock);
       move.l newLock(a4),d1
       jsr    _LVOCurrentDir(a6)
       move.l d0,oldLock(a4)
;**                Level += 1;
       addq.w #1,Level(a5)
DirLoop:
;**    {
;**            if ((ExNext(newLock,fibb)) == 0)
       move.l newLock(a4),d1   ; lock
       move.l fibb(a4),d2      ; file info block address
       jsr    _LVOExNext(a6)      ; go for the data
       tst.l  d0
       beq.s  EndDir
       tst.b  FileErr(a5)
       bne.s  EndDir
;**              if (fibb->fib_EntryType < 0)
       move.l fib_EntryType(a3),d0
       bpl.s  TypeDir3
       lea    fib_FileName(a3),a0
       jsr    FilBit
       bra.s  Join3
;**                GetDir(fibb->fib_FileName);
;**                Size += tSize;
;**                Count += tCount;
TypeDir3  lea    fib_FileName(a3),a0
       bsr    GetDir
Join3  move.l tSize(a5),d0
       add.l  d0,Size(a4)
       move.l tCount(a5),d0
       add.l  d0,Count(a4)
; collect stats?
       move.l fibb(a4),a3
       bra.s  DirLoop
;**            Level -= 1;
EndDir subq.w #1,Level(a5)
;**                newLock = CurrentDir(oldLock);
       move.l oldLock(a4),d1
       jsr    _LVOCurrentDir(a6)
       move.l d0,newLock(a4)
;**                }  /* dir */
Rejoin2:
;**              ??Count += Count;
       tst.b  FileErr(a5)
       bne.s  EndSplit1
       move.l Size(a4),d7
;**              if (Level <1 0)
       move.w Level(a5),d0
       beq.s  Dir3     ; assuming a directory
       subq.w #1,d0
       bne.s  NextItem
;**                {
;**                else
;**                      printf(" DIR %3d",Count);
Dir3   move.l OutHandle(a5),d1
       lea    DirMsg(pc),a1
       move.l a1,d2
       moveq  #DirLen,d3
       jsr    _LVOWrite(A6)
       move.l Count(a4),d0
       bsr    MakeAscii
       move.l OutHandle(a5),d1
       lea    String+5(A5),a1
       move.l a1,d2
       moveq  #5,d3
       jsr    _LVOWrite(A6)
;**                printf(" %7d %4d %s\n",Size,Blox,NameSave);
       move.l NameSave(a4),a2
       bsr    PrintStuff
;**                }
; look for file join here
NextItem:
       move.l a6,d7
       moveq  #0,d0
       move.l #$1000,d1
       move.l $4,a6
       jsr    _LVOSetSignal(a6)
       move.l d7,a6
       and.l  #$1000,d0
       beq.s  EndSplit1
       move.b #3,FileErr(a5)
EndSplit1:
;**   tSize = Size;
;**   tCount = Count;
       move.l Size(a4),tSize(a5)
       move.l Count(a4),tCount(a5)
;**        }   /* Examine OK */
;**      UnLock(newLock);
DropLock    move.l dosBase(a5),a6    ; set Dos Library
       move.l newLock(a4),d1    ; take off the lock
       jsr    _LVOUnLock(a6)
;**      }      /* Lock OK */
;**    FreeMem(fibb,INFOSIZE);
DropMem:    move.l $4,a6             ; set Exec library
       move.l fibb(a4),a1       ; memory block address
       move.l #INFOSIZE,d0      ; size of block
       jsr    _LVOFreeMem(a6)   ; release this memory
       move.l dosBase(a5),a6    ; set Dos Library
;**    }        /* Alloc OK */
GDExit unlk   A4
FilEnd rts
;**  }

FilBit move.l  a0,xName(a4)
       move.l  fib_Size(a3),d7
       tst.b   Blocker(a5)
       beq.s   noblox2
       move.l  fib_NumBlocks(a3),d7
noblox2 move.l d7,tSize(a5)
       moveq   #1,d0
       move.l  d0,tCount(a5)
;**              if (Level <1 0)
       move.w Level(a5),d0
       beq.s  pf          ; assuming a file
       subq.w #1,d0
       bne.s  FilEnd
; Check .info status
pf     tst.b  KillInf(a5)
       beq.s  PeekFile
       move.l xName(a4),a2
TryCharx  move.b (a2)+,d0
       bne.s  TryCharx
       lea    -6(a2),a2
       lea    InfoLine(pc),a1
InfLp  cmp.b  (a1)+,(a2)+
       beq.s  InfLp
       tst.b  -1(a2)
       beq.s  FilEnd
; We're gonna print the file.  Empty?  Will we look at it?
PeekFile lea   EmptyMsg(pc),a2
       tst.l  d7
       beq    FlEmp
       tst.b  Look(a5)
       bne    DoNotLook
; Open the file in order to check details
       move.l xName(a4),d1   ; filename pointer
       move.l #MODE_OLDFILE,d2  ; get a read lock
       jsr    _LVOOpen(a6)
       move.l d0,d6             ; store the file handle
       beq    FlEmp             ; couldn't get file
; Read DATASIZE bytes of the file, then close it
       move.l d6,d1             ;infile handle
       move.l DataBlk(a5),d2    ; input buffer address
       moveq  #DATASIZE,d3      ; how many bytes
       jsr    _LVORead(a6)      ; so read it
       move.l d0,d5             ; actual bytes read
       move.l d6,d1             ; inhandle
       jsr    _LVOClose(a6)       ; close the file
       lea    TextMsg(pc),a2
; check for text characters only
       move.l DataBlk(a5),a0
       moveq  #0,d3
TxLp   move.b 0(a0,d3),d0
       cmp.b  #9,d0
       beq.s  TryMore
       cmp.b  #10,d0
       beq.s  TryMore
       cmp.b  #$20,d0
       blt.s  NoText
TryMore addq.w #1,d3
       cmp.w  d3,d5
       bne.s  TxLp
       bra    FlEmp 
; Not Text - try longword start
NoText move.l (a0),d0
       lea    LdblMsg(pc),a2
       cmp.l  #$3F3,d0
       beq.s  FlEmp
; special IFF sequence
       cmp.l  #'FORM',d0
       bne.s  WordStart       
       lea    String(a5),a2
       move.l #'IFF:',(a2)
       move.l 8(a0),4(a2)
       bra.s  FlEmp
; look for magic word start
WordStart  move.w (a0),d0
       lea    WBOMsg(pc),a2
       cmp.w  #$E310,d0
       beq.s  FlEmp
       lea    FLisMsg(pc),a2
       cmp.w  #$f00,d0
       beq.s  FlEmp
       lea    WBWMsg(pc),a2
       cmp.w  #$f34c,d0
       beq.s  FlEmp
; special Basic sequence
       and.w  #$FE7F,d0
       lea    BasMsg(pc),a2
       cmp.w  #$F400,d0
       beq.s  FlEmp
; special longword-text test
       moveq  #3,d1
lngtst move.b 0(a0,d1.w),d0
       cmp.b  #$30,d0
       blt.s  DoNotLook
       cmp.b  #$7f,d0
       bgt.s  DoNotLook
       dbf    d1,lngtst
       lea    String(a5),a2
       move.l #'....',(a2)
       move.l (a0),4(a2)
       bra.s  FlEmp


DoNotLook lea FileMsg(pc),a2
FlEmp  move.l a2,d2
       move.l OutHandle(a5),d1
       moveq  #FileLen,d3
       jsr    _LVOWrite(a6)
       move.l xName(a4),a2
; PeekFile drops into PrintStuff
;     ...or PS may be called directly...
PrintStuff:
       move.l d7,d0
       bsr.s  MakeAscii
       move.l OutHandle(a5),d1
       lea    String(a5),a1
       moveq  #11,d3
       tst.b  Blocker(a5)
       beq.s  noblox3
       lea    String+4(a5),a1
       moveq  #7,d3
noblox3   move.l a1,d2
       jsr    _LVOWrite(a6)
       move.w Level(a5),d0
       bne.s  Flush
       move.l OutHandle(a5),d1
       lea    SpaceMsg(pc),a1
       move.l a1,d2
       moveq  #SpaceLen,d3
       jsr    _LVOWrite(A6)
Flush  move.l OutHandle(a5),d1
       move.l a2,d2
       moveq  #0,d3
TryChara  move.b 0(a2,d3),d0
       beq.s  FoundEnd
       addq.b #1,d3
       bra.s  TryChara
FoundEnd  jsr    _LVOWrite(A6)
       move.l OutHandle(a5),d1
       lea    MsgNewLine(pc),a1
       move.l a1,d2
       moveq  #NewLineLen,d3
       jsr    _LVOWrite(A6)
PrEnd  rts

MakeAscii:
       moveq  #$20,d1
       lea    String(a5),a1
       moveq  #11,d2
SpacedOut   move.b d1,0(a1,d2)
       dbf    d2,SpacedOut
       moveq  #9,d2
DigLoop     swap   d0
       moveq  #0,d1
       move.w d0,d1
       beq.s  Skipper
       divu   #10,d1
Skipper     move.w d1,d0
       swap   d0
       move.w d0,d1
       divu   #10,d1
       move.w d1,d0
       swap   d1
       or.b   #$30,d1
       move.b d1,0(a1,d2)
       tst.l  d0
       dbeq   d2,DigLoop
       rts

InfoLine    dc.b   '.info.'
MsgNewLine  dc.b   $0a
NewLineLen  equ    *-MsgNewLine
SpaceMsg    dc.b   $20
SpaceLen    equ    *-SpaceMsg
DirMsg      dc.b   'DIR'
DirLen      equ    *-DirMsg
PromptMsg   dc.b   'ViewDir (by Jim Butterfield) V2.0',$0a
            dc.b   'FORMAT:  ViewDir [-b -i -t] directory',$0a
PromptLen   equ    *-PromptMsg
TextMsg     dc.b   'TextFile'
LdblMsg     dc.b   'Loadable'
WBOMsg      dc.b   'WBObject'
WBWMsg      dc.b   'WBWindow'
BasMsg      dc.b   'AmiBasic'
FLisMsg     dc.b   'FontList'
FileMsg     dc.b   'FILE    '
FileLen     equ    *-FileMsg
EmptyMsg    dc.b   'Empty   ',$0a
EmptyLen    equ    *-EmptyMsg
NoMemMsg    dc.b   'Out of Memory',$0a
NoMemLen    equ    *-NoMemMsg
NoFileMsg   dc.b   'Can t find file.',$0a
NoFileLen   equ    *-NoFileMsg
CtrlCMsg    dc.b   '^C',$0a
CtrlCLen     equ    *-CtrlCMsg
dosname     dc.b   'dos.library',0
            end

