Dim ProgramID$/"Flex to SDOS file conversion utility program V1.0"/

REM -  A utility to initialize FLEX disks and copy files between
REM -  SDOS and FLEX disks while running under SDOS V1.4 BASIC
REM -  BY Ron Whites

REM -  Directory entry Layout Equates

dim FlexDirEntry$(24),FlexBuffer$(256),SdosFile$(24),Flexfile$(12)
dim FlexExt$(3),Null$(256)
dim RandomArray$(508)

dim FlexDrive$(16),FlexDisk/1/

dim FileName/0/,Ext/8/,Fileatrib/11/,StartAddr/13/,EndAddr/15/
dim Filesize/17/,Randomflag/19/,Creation/21/,DirEntrySz/24/

dim DirEntryPerSector/10/,DirDisp/16/,LDirDisp/232/

dim Dsector/5/,Dtrack/0/,Sector/1/,Track/0/
dim SdosFile/14/, FfreeSector/1/, FfreeTrack/1/

dim CCSetMapAlgorithm$/:e,8,0,:12/,FlexMapAlgorithm$/:00,:06/
dim CCUnlockDisk$/:e,4,0,:10/

        Let Len(Null$) = 256
        For I = 1 to 256
          Let Null$(I) = :00
        Next I

FlexUtility:
        If col(0) > 1 Then
          Input "" FlexDrive$
          Print ProgramID$
        Else
          Print ProgramID$
          Input "Name of disk device containing Flex diskette: " FlexDrive$
        Fi

        Open #FlexDisk,FlexDrive$
        Syscall #FlexDisk,CCSetMapAlgorithm$,FlexMapAlgorithm$
        Syscall #FlexDisk,CCUnlockDisk$

FlexUtilityNextCommand:
        Input "Flex Utility>" FlexBuffer$
        Let FlexBuffer$ = Uppercase$(FlexBuffer$)
        If FlexBuffer$ = "EXIT" Then exit
        ElseIf Find(FlexBuffer$,"RCOPY") =1 Then CopytoFlexR
        ElseIf Find(FlexBuffer$,"SCOPY") =1 Then CopytoFlexS
        ElseIf Find(FlexBuffer$,"FCOPY") =1 Then CopytoSdos
        ElseIf Find(FlexBuffer$,"DELETE") = 1 Then FlexDelete
        ElseIf FlexBuffer$ = "FILES" Then FlexList
ShowHelpMessage:
        Print "?? Invalid Flex Utility command."
        Print "Only the following commands are valid here;"
        Print "FILES  - to show files on flex disk"
        Print "RCOPY  - to copy SDOS file to random FLEX file"
        Print "SCOPY  - to copy SDOS file to sequential FLEX"
        Print "FCOPY  - to copy file from FLEX to SDOS"
        Print "DELETE - to delete file from FLEX"
        Print "EXIT   - to exit this utility"
        Goto FlexUtilityNextCommand

SearchFlex:

        EndChain = False
Rem - starting with first directory sector
        Csector  = Dsector
        Ctrack   = Dtrack
        UsedDir  = 0
        EmptyDir = 0

        Until EndChain Do
Rem - read next directory sector
          Gosub ReadSectorF
Rem - examine all directory slots
          For DirEntry = DirDisp to LDirDisp Step DirEntrySz
            If FlexBuffer$(DirEntry+Filename) = :00 Then
              EmptyDir = EmptyDir + 1
              If EmptyDir = 1 Then
Rem - save location of first avialable directory slot
                Let DirTrack = Ctrack
                Let DirSector = Csector
                Let DirEntrySave = DirEntry
              Fi
              Cycle DirEntry
            Fi
            UsedDir = UsedDir + 1
            If FlexFile$ = "" Then
Rem - If no filename then dump entry, we are doing a files
              Let FlexDirEntry$ = FlexBuffer$(DirEntry,DirEntrySz)
              Print FlexDirEntry$(Filename,8);".";
              Print FlexDirEntry$(Ext,3);" ";
              Print Hex$(FlexDirEntry$(Fileatrib));" ";
       Print FlexDirEntry$(Startaddr) * 256 + FlexDirEntry$(Startaddr+1);" "
       Print FlexDirEntry$(Endaddr) * 256 + FlexDirEntry$(Endaddr+1);" "
       Print FlexDirEntry$(Filesize) * 256 + FlexDirEntry$(Filesize+1)
            Else
Rem - If filename and match then return
              If FlexFile$ = FlexBuffer$(DirEntry+Filename,8) and ...
&               FlexExt$ = FlexBuffer$(DirEntry+Ext,3) Then
                Let FlexDirEntry$ = FlexBuffer$(DirEntry,DirEntrySz)
                Return
              Fi
            Fi
          Next DirEntry
          Gosub NextFlexSector
        End
Rem - If searched directory and found no empty slot
Rem - save last track and sector to extend, for new directory
        If EmptyDir = 0 Then
          Let DirTrack = Ctrack
          Let DirSector = Csector
        Fi
        Return

FlexDelete:
        FlexFile$ = Right$(FlexBuffer$,8)
        Gosub PadandBreak
        Gosub SearchFlex
        If EndChain Then
          Print "File not found"
          Goto FlexUtilityNextCommand
        fi
Rem - Zero directory entry deleting
        Let FlexBuffer$(DirEntry,DirEntrySz) = Null$
        Gosub WriteSectorF
        Let Csector = FfreeSector
        Let Ctrack = FfreeTrack

Rem - Below we place file on front of free chain

Rem - Read Free chain and save
        Gosub ReadSectorF
        Let Firstsector = FlexBuffer$(sector)
        Let Firsttrack = FlexBuffer$(track)
Rem - Read Last sector in file
        Let Csector = FlexDirEntry$(Endaddr+Sector)
        Let Ctrack  = FlexDirEntry$(Endaddr+Track)
        Gosub ReadSectorF
        If EndChain = False Then
          Print "Corrupt file, Ending sector has non-zero links"
          Goto FlexUtilityNextCommand
        Fi
Rem - Point last in file at first of free chain
        Let FlexBuffer$(Sector) = Firstsector
        Let FlexBuffer$(Track) = Firsttrack
        Gosub WriteSectorF
Rem - Point Free chain at start of file
        Let Csector = FFreeSector
        Let Ctrack = FFreeTrack
        Gosub ReadSectorF
        Let FlexBuffer$(Sector) = FlexDirEntry$(Startaddr+Sector)
        Let FlexBuffer$(Track) = FlexDirEntry$(Startaddr+Track)
        Gosub WriteSectorF
        Goto FlexUtilityNextCommand

Rem - Copy file to SDOS

CopytoSdos:
        P = Find(FlexBuffer$, " TO ")
        If P > 0 Then
          SdosFile$ = Right$(FlexBuffer$,P+4)
          FlexFile$ = FlexBuffer$(7,P-7)
        Else Goto ShowHelpMessage
        Gosub PadandBreak
        Gosub SearchFlex
        If EndChain Then
          Print "File not found"
          Goto FlexUtilityNextCommand
        fi
        Create #SDOSFILE, SdosFile$
        Csector = FlexDirEntry$(Startaddr+sector)
        Ctrack = FlexDirEntry$(Startaddr+track)
        EndChain = False
        If FlexDirEntry$(Randomflag) <> :00 Then
Rem - Skip random file index sectors
          Gosub ReadSectorF
          Gosub NextFlexSector
          Gosub ReadSectorF
          Gosub NextFlexSector
        Fi
Rem - Copy 254 byte sector data to SDOSfile
        Until EndChain Do
          Gosub ReadSectorF
          Gosub NextFlexSector
          Gosub WriteSectorS
        End
        Close #SdosFile
        Goto FlexUtilityNextCommand

Rem - Copy File to Flex
Rem - Build Random or sequential

CopytoFlexR:
        RandomF = True
        Goto 1000
CopytoFlexS:
        RandomF = False
1000
        P = Find(FlexBuffer$, " TO ")
        If P > 0 Then
          FlexFile$ = Right$(FlexBuffer$,P+4)
          SdosFile$ = FlexBuffer$(7,P-7)
        Else Goto ShowHelpMessage
        Gosub PadandBreak
        Gosub SearchFlex
        If EndChain = True Then
          Print "Flex file already exists cannot copy"
          Goto FlexUtilityNextCommand
        fi
Rem - if found no empty directory slots allocate
Rem - a new directory sector
        If EmptyDir = 0 Then
          Csector = FFreeSector
          Ctrack = FFreetrack
          Gosub ReadSectorF
Rem - Set Csector with first in free chain
          Gosub NextFlexSector
          If EndChain = True Then Goto OutofDisk
Rem - Where free chain will point
          Let NextFreeSector = FlexBuffer$(Sector)
          Let NextFreetrack = FlexBuffer$(Track)
Rem - Zero first in free chain for use as directory sector
          Let FlexBuffer$ = Null$
          Gosub WriteSectorF
Rem - Save first in free chain location and read last already in directory
          Let FirstSector = Csector
          Let FirstTrack = Ctrack
          Let Csector = DirSector
          Let Ctrack = DirTrack
          Gosub ReadSectorF
Rem - Point to new directory sector
          Let FlexBuffer$(Sector) = FirstSector
          Let FlexBuffer$(Track) = FirstTrack
          Gosub WriteSectorF
Rem - Adjust free chain
          Let Csector = FfreeSector
          Let Ctrack = FfreeTrack
          Gosub ReadSectorF
          Let FlexBuffer$(Sector) = NextFreeSector
          Let FlexBuffer$(Track) = NextFreeTrack
Rem - Save where first free slot is
          Gosub WriteSectorF
          Let DirEntrySave = DirDisp
          Let DirTrack = FirstTrack
          Let DirSector = FirstSector
        Fi
        OPEN #Sdosfile, SdosFile$
        Csector = FFreeSector
        Ctrack = FFreetrack
        Gosub ReadSectorF
Rem - Sector count for how many sectors in flex file
        Let RandomArray$ = Null$
        Let RandomArray$(255,254) = Null$
        SectorCt = 0
Rem - Allocate 2 index sectors for random
        If RandomF = True Then
          Gosub NextFlexSector
          Gosub ReadSectorF
          If EndChain = True Then Goto OutofDisk
          Gosub NextFlexSector
          Gosub ReadSectorF
          If EndChain = True Then Goto OutofDisk
          Let SectorCt = SectorCt + 2
        Fi
        Until EndChain Or EndFile Do
          Gosub NextFlexSector
Rem - Read flex sector from free chain establishing links
          Gosub ReadSectorF
Rem - Read SDOS bytes into flex sector and pad with nulls for last sector
          Gosub ReadSectorS
          If EndFile Then
            Let Csector = FFreeSector
            Let Ctrack = FFreeTrack
            Gosub ReadSectorF
            Let NextFreeSector = FlexBuffer$(Sector)
            Let NextFreeTrack = FlexBuffer$(Track)
            Let FlexBuffer$(Sector) = :00
            Let FlexBuffer$(Track) = :00
          Fi
          Gosub WriteSectorF
          Let SectorCt = SectorCt + 1
Rem - Assert: Ctrack preceeds Csector
          Let RandomArray$(Len(RandomArray$)) = Ctrack
          Let RandomArray$(Len(RandomArray$)) = Csector
          If EndFile Then
Rem - Remove from free chain
            Let FlexBuffer$(Sector) = NextFreeSector
            Let FlexBuffer$(Track) = NextFreeTrack
            Gosub WriteSectorF
Rem - Build new directory entry
            Let FlexDirEntry$(Filename,8) = Flexfile$
            Let FlexDirEntry$(Ext,3) = FlexExt$
            Let FlexDirEntry$(Fileatrib) = :00
            Let FlexDirEntry$(Fileatrib+1) = :00
            Let FlexDirEntry$(Startaddr+sector) = Firstsector
            Let FlexDirEntry$(Startaddr+track) = Firsttrack
     Let FlexDirEntry$(Endaddr+track) = RandomArray$(Len(RandomArray$)-1)
     Let FlexDirEntry$(Endaddr+sector) = RandomArray$(Len(RandomArray$))
            Let FlexDirEntry$(Filesize) = SectorCt**-8
            Let FlexDirEntry$(Filesize+1) = SectorCt & :FF
            Let FlexDirEntry$(RandomFlag) = :00
            If RandomF = True Then Let FlexDirEntry$(RandomFlag) = :02
            Let FlexDirEntry$(Creation) = :00
            Let FlexDirEntry$(Creation+1) = :00
            Let FlexDirEntry$(Creation+2) = :00
            Let CTrack = DirTrack
            Let Csector = DirSector
            Gosub ReadSectorF
            Let FlexBuffer$(DirEntrySave,24) = FlexDirEntry$
            Gosub WriteSectorF
            If RandomF = True Then
Rem - Write Random index
              Csector = FirstSector
              Ctrack = FirstTrack
              Gosub ReadSectorF
              Let FlexBuffer$(3,254) = RandomArray$
              Gosub WriteSectorF

              Gosub NextFlexSector
              Gosub ReadSectorF
              Let FlexBuffer$(3,254) = RandomArray$(255,254)
              Gosub WriteSectorF
            Fi
          Fi
        End
        If EndFile = False Then
OutofDisk:
          Print "Not room on Flex disk"
        Fi
        Close #Sdosfile
        Goto FlexUtilityNextCommand

FlexList:
        Let FlexFile$ = ""
        Print
        Print "Filename..."
        Gosub SearchFlex
        Print "Empty directory slots: ";EmptyDir
        Print "Used directory slots: ";UsedDir
        Goto FlexUtilityNextCommand

PadandBreak:
        P = FIND(FlexFile$,".")
        IF P > 0 Then
          Let FlexExt$ = Right$(FlexFile$,P+1)
          Let Len(FlexFile$) = P - 1
        ELSE
          Let FlexExt$ = ""
        FI

        I = Len(FlexExt$)
        If I < 3 Then
          Let Len(FlexExt$) = 3
          Let FlexExt$(I+1,3-I) = Null$
        Fi
        I = Len(FlexFile$)
        If I < 8 Then
          Let Len(FlexFile$) = 8
          Let FlexFile$(I+1,8-I) = Null$
        Fi
        Return

ReadSectorS:
        Let FlexBuffer$(3,254) = Null$
        Endfile = False
        If Error When Read #Sdosfile, Flexbuffer$(3,254) Then endfile = True
        Return

WriteSectorS:
        If EndChain Then
          For I = 256 to 3 Step -1 ...
&             While FlexBuffer$(I) <> :00 Do ! Supress Nulls
        Else I = 256
        Write #Sdosfile, Flexbuffer$(3,I-2)
        Return

Rem - Read Current Sector from Flex

ReadSectorF:
        Rem Scall to read sector
        Return

WriteSectorF:
        Rem Scall to write sector
        Return

NextFlexSector:
        Csector = FlexBuffer$(Sector)
        Ctrack = FlexBuffer$(Track)
        EndChain = False
        If Csector = :00 and Ctrack = :00 Then EndChain = True
        Return

        END
