'=========================================================================== ' Subject: DISK FORMATTING PROGRAM FOR PB Date: 12-28-99 (18:05) ' Author: Dieter Folger Code: PB ' Origin: folger@bnv-bamberg.de Packet: DISK.ABC '=========================================================================== '---------------------------------------------------------------------------- ' PBFORMAT.BAS is a complete disk formatting program based upon ' DISK13IO.PAS written by Kurt Diesch using Turbo Pascal. ' PBFORMAT allows to format 360k / 1.2M / 720k / 1.44M disks in ' drives A or B. ' Changes to DISK13IO.PAS: A special boot sector is written that ' boots from hard disk when no system is found on floppy. ' PBFORMAT is freeware (c) 1995 by D. Folger ' Use at your own risk. '---------------------------------------------------------------------------- $COMPILE EXE $ERROR ALL OFF $OPTIMIZE SPEED DEFINT A - Z %False = 0 : %True = NOT %False '==== main program ======================================================== IF DosVersion! < 3.3 THEN PRINT "Need MS-DOS 3.3 or newer" : END END IF CY=CSRLIN:Cx=POS(0) SaveScreen Temp$ Cm$ = UCASE$(COMMAND$) IF Cm$ = "" THEN PRINT : Print " -þ- P B F O R M A T -þ-" PRINT PRINT " Drive A or B (or ESC to quit): "; DO DO : K$ = UCASE$(INKEY$) : LOOP UNTIL LEN(K$) IF K$ = CHR$(27) THEN GOTO Quit LOOP UNTIL INSTR("AB", K$) PRINT K$: PRINT DriveNumber = ASC(K$) - 65 PRINT " 1 = 360K 5¬" + CHR$(34) + " 3 = 720K 3«" + CHR$(34) PRINT " 2 = 1.2M 5¬" + CHR$(34) + " 4 = 1.44M 3«" + CHR$(34) PRINT : Print " Disk size 1 - 4 (or ESC to quit): "; DO DO : K$ = INKEY$ : LOOP UNTIL LEN(K$) IF K$ = CHR$(27) THEN GOTO Quit LOOP UNTIL INSTR ("1234", K$) PRINT K$ : PRINT DiskType = VAL(K$) DoVerify = %True END IF IF LEN(Cm$) THEN IF INSTR(Cmd$,":") THEN DriveNumber = ASC(MID$(Cm$,INSTR(Cm$,":")-1,1)) - 65 IF DriveNumber < 0 OR DriveNumber > 1 THEN Syntax = %True DiskType = VAL(MID$(Cm$,INSTR(Cm$, "/1")+1,1)) + _ VAL(MID$(Cm$,INSTR(Cm$, "/2")+1,1)) + _ VAL(MID$(Cm$,INSTR(Cm$, "/3")+1,1)) + _ VAL(MID$(Cm$,INSTR(Cm$, "/4")+1,1)) IF DiskType < 1 OR DiskType > 4 THEN Syntax = %True IF INSTR(Cm$, "/V") THEN DoVerify = %True IF INSTR(Cm$, "/?") THEN Syntax = %True END IF IF Syntax THEN PRINT "Syntax: PBFORMAT Drive /DiskType [/V] [/Q]" PRINT " Drive = A: or B: PRINT " Disktype: /1 = 360k /2 = 1.2M PRINT " /3 = 720k /4 = 1.44M PRINT " /V = Verify END END IF PRINT " Insert disk in drive "; CHR$(DriveNumber + 65); PRINT " and press RETURN (or ESC to quit)"; DO DO: K$=INKEY$: LOOP UNTIL LEN(K$) IF K$ = CHR$(27) THEN END LOOP UNTIL K$ = CHR$(13) CLS F = FormatDisk (DiskType, DriveNumber, DoVerify) IF F = %False THEN el = 255 Quit: RestoreScreen Temp$ END el 'end program with errorlevel '=========================================================================== FUNCTION FormatDisk (BYVAL DType, BYVAL Drive, DoVerify) PUBLIC SHARED '--------------------------------------------------------------------------- InitData (DType) FormatDisk = %False SELECT CASE DType ' determine drive type CASE 1 ' 360k or 1.2M drive? ! MOV AX, &H1500 ! MOV DX, Drive ! INT &H13 ! MOV Dt, AH SELECT CASE Dt CASE 1 ' 360K in 360K drive ! MOV AX, &H1701 CASE 2 ' 360K in 1.2M drive ! MOV AX, &H1702 CASE ELSE 'invalid type IF Error13 (251,0) THEN EXIT FUNCTION END SELECT CASE 2 ' 1.2M in 1.2M drive ! MOV AX, &H1703 CASE 3,4 ' 720K or 1.44M in 720K or 1.44M drive ! MOV AX, &H1704 END SELECT Spt = Spt(DType) Tpd = Tpd(DType) ! MOV DX, Drive ! INT &H13 ! MOV AX, &H1800 ! MOV DX, Drive ! MOV CH, Tpd ! MOV CL, Spt ! INT &H13 ResetDrive Drive BadSectors = 0 : Track = 0 : Sector = 1 '----------------- ' Formatting '----------------- IF Tpd(DType) = &h27 THEN Sx = 2 Box 8,22,13-Sx,35,15,3 VIEW TEXT (22,8)-(57,25) LOCATE 2,5 Print " -þ- P B F O R M A T -þ-" : PRINT Y = 2 : X = 9 COLOR 0,3 FOR i=1 TO (Tpd(DType)+1)/20 LOCATE Y + i, X PRINT STRING$(20,176) NEXT COLOR 15,3 Y = 1 : X = 1 Fat$ = STRING$(Spf(DType) * 512, CHR$(0)) MID$(Fat$,1,3) = CHR$(Fid(DType)) + CHR$(&HFF) + CHR$(&HFF) RTotal = 2 * Spf(DType) + Dsc(DType) ' number of reserved sectors IF QuickFormat = %False THEN LOCATE 8-Sx,3 : PRINT " Formatting";Tpd(DType)+1;"tracks" DO Side = 0 LOCATE 9-Sx,3 : PRINT " Formatting Track "; PRINT USING "##"; Track + 1; DO LOCATE 2+Y,8+X : IF Side=0 then COLOR 12,3 ELSE COLOR 14,3 PRINT "²"; Chrn$="" FOR Sector = 1 TO Spt(DType) Chrn$=Chrn$ + CHR$(Track)+ CHR$(Side) + _ CHR$(Sector) + CHR$(Ssz(Dtype)) NEXT COLOR 15,3 LOCATE 9-Sx, 24: PRINT "Side"; Side; Offs& = STRPTR(Chrn$) : Segm& = STRSEG(Chrn$) Tries = 0 : Done = %False DO ! MOV AH,&H05 ;Format ! MOV AL, Spt ! MOV CH, Track ! MOV CL, 1 ! MOV DH, Side ! MOV DL, Drive ! MOV ES, Segm& ! MOV BX, Offs& ! INT &H13 ! MOV FormatError, AH IF FormatError THEN INCR Tries IF Tries > 2 THEN IF Error13 (FormatError,1) THEN EXIT FUNCTION ELSE Tries = 0 END IF ELSE ResetDrive (Drive) END IF ELSE Done = %True END IF LOOP UNTIL Done INCR Side LOOP UNTIL Side = 2 '------------------- ' Verifying '------------------- IF DoVerify THEN Maxbad = 100 : Side = 0 LOCATE 9-Sx, 3 : PRINT " Verifying "; DO V = VerifySectors (DType,Drive,Track, Side,1,Spt(DType)) IF V = 0 THEN IF Track = 0 THEN IF Error13 (253,0) THEN EXIT FUNCTION Sector = 0 DO INCR Sector V = VerifySectors (DType,Drive,Track,Side,Sector,1) IF V = 0 THEN MarkBadSector DType, Track, Side, Sector COLOR 12,3 LOCATE 10-Sx, 3 : PRINT " Bad sectors"; BadSectors LOCATE Y+2,X+8 : PRINT "²":COLOR 15,3 IF BadSectors > MaxBad THEN IF Error13 (252,0) THEN EXIT FUNCTION END IF END IF LOOP UNTIL Sector = Spt(DType) END IF INCR Side LOOP UNTIL Side = 2 END IF IF Side=2 THEN INCR X : IF X MOD 21 = 0 THEN X = 1 : INCR Y INCR Track LOOP UNTIL Track > Tpd(DType) END IF '---------------------------------- ' Writing boot and FATs '---------------------------------- W = WriteSectors (DType, Drive, 0, 0, 1, 1, BootRecord$) RWritten = 0 : Track = 0 : Side = 0 : Sector = 2 : FATNum = 0 DO IF Sector > Spt(DType) THEN Sector = 1 : INCR Side IF RWritten < Spf(DType) * 2 THEN IF FATNum > Spf(DType) - 1 THEN FATNum = 0 ELSE MID$(FAT$,1,512) = STRING$(512, CHR$(0)) IF RWritten = 2 * SPF(DType) THEN VIEW TEXT (1,1)-(80,25) Box 22-Sx,10,2,60,15,3 LOCATE 23-Sx,11 PRINT "Volume name (11 characters or RETURN for none): ..........." LOCATE 23-Sx,59,5 VLabel$ = "" DO K$ = INKEY$ IF K$ = CHR$(8) THEN LOCATE 23-Sx, POS(a) - 1 : PRINT " "; LOCATE 23-Sx, POS(a) - 1 END IF IF K$ > CHR$(31) THEN PRINT K$; VLabel$ = VLabel$ + UCASE$(K$) END IF LOOP UNTIL K$ = CHR$(13) VLabel$=LEFT$(VLabel$+SPACE$(11),11)+CHR$(8) MID$(Fat$,1,12) = VLabel$ MID$(Fat$,23,4) = Packtime$ END IF FatNum = 0 END IF W = WriteSectors (DType, Drive, Track, Side, Sector, 1, _ MID$(FAT$,1 + Fatnum * 511, 512)) IF W THEN INCR Sector : INCR RWritten : INCR FatNum LOOP UNTIL RTotal = RWritten '-------------------------- ' Give summery and clean up '-------------------------- RestoreTable DiskInfo Drive, Total&, Free& LOCATE 18-Sx,23,0 PRINT " "; Total&;" bytes total " LOCATE 19-Sx,23 PRINT " "; Free&; " bytes available" LOCATE 20-Sx,23 IF BadSectors THEN PRINT " "; BadSectors * 512 ; "bytes marked as bad" FormatDisk = %True LOCATE 23-Sx,11 PRINT " Press a key " WaitKey END FUNCTION '-------------------------------------------------- SUB MarkBadSector (Dtype, Track, Side, Sector) PUBLIC SHARED '-------------------------------------------------- BadMark = &H0FF7 ' bad cluster mark ' CNum = cluster number ' FOffs = offset into fat for this cluster ' FVal = FAT value for this cluster ' OldVal = Old FAT value for this cluster CNum = (((((Track * 2) + Side) * Spt(DType)) + Sector - RTotal - 2) _ \ ASC(MID$(Brd$(DType),1, 2))) + 2 IF CNum > 1 THEN ' make sure it is in data space Foffs = ((CNum * 3) \ 2) +1 FVal$ = MID$(Fat$, FOffs,2) FVal& = ASC(FVal$) IF CNum MOD 2 > 0 THEN OldVal = FVal& AND (BadMark * (2^4)) ELSE OldVal = FVal& AND BadMark END IF IF OldVal = 0 THEN ' if not already marked bad, mark it IF CNum MOD 2 > 0 THEN FVal& = FVal& OR BadMark * (2 ^4) ELSE FVal& = FVal& OR BadMark END IF FVal$=RIGHT$("0000"+HEX$(FVal&),4) FVal$ = CHR$(VAL("&H"+(MID$(FVal$,3)))) + _ CHR$(VAL("&H"+(LEFT$(FVal$,2)))) MID$(Fat$,FOffs,2)=FVal$ INCR BadSectors, ASC(LEFT$(Brd$(DType),1)) ' Count bad sector END IF END IF END SUB '----------------------------------------------------------------------------- FUNCTION PackTime$ ' format time and date as unsigned integer ' and return as string '----------------------------------------------------------------------------- Year = VAL(MID$(DATE$,7)) Month = VAL(LEFT$(DATE$,2)) Day = VAL(MID$(DATE$,4,2)) : CurDate = (Year - 1980) * 512 + Month * 32 + Day D$ = HEX$(CurDate) Seconds = VAL(MID$(TIME$,7)) Minutes = VAL(MID$(TIME$,4,2)) Hours = VAL(LEFT$(TIME$,2)) CurTime = VAL("&B"+ BIN$(Hours) + RIGHT$("00000000000" + BIN$(Minutes) + _ RIGHT$("00000"+BIN$(Seconds\2),5),11)) T$ = HEX$(CurTime) PackTime$ = CHR$(VAL("&H"+MID$(T$,3))) + CHR$(VAL("&H"+LEFT$(T$,2))) + _ CHR$(VAL("&H"+MID$(D$,3))) + CHR$(VAL("&H"+LEFT$(D$,2))) END FUNCTION '-------------------------------------------------------------------- SUB RestoreTable PUBLIC SHARED ' Restore formatting table '-------------------------------------------------------------------- DEF SEG = DtSegm POKE$ DtOffs, Dfpt$ DEF SEG END SUB '-------------------------------------------------- SUB ResetDrive (Drive) '-------------------------------------------------- ! MOV AX, 0 ! MOV Dx, Drive ! INT &H13 END SUB '-------------------------------------------------- FUNCTION WriteSectors (BYVAL DType,BYVAL Drive, BYVAL Track, BYVAL Side, _ BYVAL SSect, BYVAL NSect, Buffer$) PUBLIC SHARED ' write absolute disk sectors '-------------------------------------------------- WriteSectors = %False Tries = 0 : Done = %False Segm& = STRSEG(Buffer$) : Offs& = STRPTR(Buffer$) DO ! MOV AH,3 ! MOV AL, Nsect ! MOV BX, Offs& ! MOV CH, Track ! MOV CL, SSect ! MOV DH, Side ! Mov DL, Drive ! MOV ES, Segm& ! INT &H13 ! MOV WriteError, AH IF WriteError <> 0 THEN INCR Tries IF Tries > 2 THEN IF Error13 (WriteError,1) THEN EXIT FUNCTION ELSE Tries = 0 ELSE ResetDrive (Drive) END IF ELSE Done = %True END IF LOOP UNTIL Done WriteSectors = %True END FUNCTION '-------------------------------------------------- FUNCTION VerifySectors (BYVAL DType, BYVAL Drive, BYVAL Track, BYVAL Side, _ BYVAL SSect, BYVAL NSect) PUBLIC SHARED '-------------------------------------------------- BUFF$ = STRING$(4000,CHR$(0)) Offs& = STRPTR(Buff$): Segm& = STRSEG(Buff$) VerifySectors = %False Done = %False Tries = 0 DO ! MOV AH,4 ! MOV AL, Nsect ! MOV BX, Offs& ! MOV CH, Track ! MOV CL, Ssect ! MOV DH, Side ! Mov DL, Drive ! MOV ES, Segm& ! INT &H13 ! MOV VerifyError, AH IF VerifyError THEN INCR Tries IF Tries > 5 THEN IF Error13 (VerifyError,1) THEN EXIT FUNCTION ELSE Tries = 0 ELSE ResetDrive (Drive) END IF ELSE Done = %True END IF LOOP UNTIL Done VerifySectors = %True END FUNCTION '---------------------------------------------------------------------------- SUB InitData (DType) PUBLIC SHARED '---------------------------------------------------------------------------- DIM Ssz(1:4), Spt(1:4), Tpd(1:4), Spf(1:4), Dsc(1:4), Fid(1:4), Brd$(1:4) Ssz(1) = &H02 : Ssz(2) = &H02 : Ssz(3) = &H02 : Ssz(4) = &H02 'Sector size Spt(1) = &H09 : Spt(2) = &H0F : Spt(3) = &H09 : Spt(4) = &H12 'Sectors/track Tpd(1) = &H27 : Tpd(2) = &H4F : Tpd(3) = &H4F : Tpd(4) = &H4F 'Tracks/disk Spf(1) = &H02 : Spf(2) = &H07 : Spf(3) = &H03 : Spf(4) = &H09 'Sectors/FAT Dsc(1) = &H07 : Dsc(2) = &H0E : Dsc(3) = &H07 : Dsc(4) = &H0E 'Dirs/Sectors Fid(1) = &HFD : Fid(2) = &HF9 : Fid(3) = &HF9 : Fid(4) = &HF0 'FAT identity Brd$(1) = CHR$(&H02)+CHR$(&H01)+CHR$(&H00)+CHR$(&H02)+CHR$(&H70)+CHR$(&H00)+ _ CHR$(&HD0)+CHR$(&H02)+CHR$(&HFD)+CHR$(&H02)+CHR$(&H00)+CHR$(&H09)+ _ CHR$(&H00)+CHR$(&H02) Brd$(2) = CHR$(&H01)+CHR$(&H01)+CHR$(&H00)+CHR$(&H02)+CHR$(&HE0)+CHR$(&H00)+ _ CHR$(&H60)+CHR$(&H09)+CHR$(&HF9)+CHR$(&H07)+CHR$(&H00)+CHR$(&H0F)+ _ CHR$(&H00)+CHR$(&H02) Brd$(3) = CHR$(&H02)+CHR$(&H01)+CHR$(&H00)+CHR$(&H02)+CHR$(&H70)+CHR$(&H00)+ _ CHR$(&HA0)+CHR$(&H05)+CHR$(&HF9)+CHR$(&H03)+CHR$(&H00)+CHR$(&H09)+ _ CHR$(&H00)+CHR$(&H02) Brd$(4) = CHR$(&H01)+CHR$(&H01)+CHR$(&H00)+CHR$(&H02)+CHR$(&HE0)+CHR$(&H00)+ _ CHR$(&H40)+CHR$(&H0B)+CHR$(&HF0)+CHR$(&H09)+CHR$(&H00)+CHR$(&H12)+ _ CHR$(&H00)+CHR$(&H02) FOR i = 1 to 177 READ B$ Boot$ = Boot$ + CHR$(VAL("&H"+B$)) NEXT BootRecord$ = Boot$ + STRING$(333,CHR$(0)) + CHR$(85) + CHR$(170) MID$(BootRecord$, 14,14) = Brd$(DType) ' Insert variable part of boot record ' Change disk parameter table DEF SEG = 0 DtOffs = PEEK(120) + PEEK(121) * 256 DtSegm = PEEK(122) + PEEK(123) * 256 DEF SEG = DtSegm Dfpt$ = PEEK$(&H522,11) ' Save table that we can restore it later SELECT CASE DType ' set gap length for formatting CASE 1 : POKE DtOffs + 7, &H50 ' 360K CASE 2 : POKE DtOffs + 7, &H54 ' 1.2M CASE 3,4 : POKE DtOffs + 7, &H6C ' 720K or 1.44M END SELECT POKE DtOffs + 4, Spt(DType) ' sectors per track POKE DtOffs + 8, 247 ' formatting char (÷) DEF SEG ' boot record data DATA EB,29,90,50,42,46,4F,52,4D,41,54,00,02,02,01,00 DATA 02,70,00,D0,02,FD,02,00,09,00,02,00,00,00,00,00 DATA 02,70,00,D0,02,FD,02,00,09,00,02,00,00,00,00,00 DATA 00,00,00,00,00,00,00,00,00,00,00,33,C9,8E,D9,8E DATA C1,FA,8E,D1,BC,00,7C,FB,C6,06,40,04,01,8B,F4,BF DATA 00,7E,B5,01,FC,F3,A5,E9,00,02,8B,DC,41,BA,80,00 DATA B8,01,02,CD,13,72,0A,81,3E,FE,7D,55,AA,75,02,FF DATA E3,E8,2C,00,49,6E,73,65,72,74,20,73,79,73,74,65 DATA 6D,20,64,69,73,6B,20,61,6E,64,20,70,72,65,73,73 DATA 20,61,6E,79,20,6B,65,79,20,20,20,20,20,20,20,00 DATA 5E,AC,22,C0,74,06,B4,0E,CD,10,EB,F5,32,E4,CD,16 DATA B8,0D,0E,CD,10,B8,20,0A,32,FF,B9,50,00,CD,10,CD DATA 19 END SUB '----------------------------------------------------------------------------- SUB Waitkey '----------------------------------------------------------------------------- DO : K$ = INKEY$ : LOOP UNTIL LEN(K$) END SUB '----------------------------------------------------------------------------- FUNCTION Error13 (ErrNum, Ask) PUBLIC SHARED ' Show error and allow to retry '----------------------------------------------------------------------------- Error13 = %True SELECT CASE ErrNum CASE 1 : ErrMsg$ = "Invalid drive" CASE 2 : ErrMsg$ = "Bad address mark" CASE 3 : ErrMsg$ = "Write protect error" CASE 4 : ErrMsg$ = "Bad sector" CASE 8 : ErrMsg$ = "DMA failure" CASE 16 : ErrMsg$ = "Bad CRC check" CASE 32 : ErrMsg$ = "Controller failure" CASE 64 : ErrMsg$ = "Bad seek" CASE 128 : ErrMsg$ = "Drive not ready" CASE 251 : ErrMsg$ = "Invalid media type" CASE 252 : ErrMsg$ = "Too many bad sectors" CASE 253 : ErrMsg$ = "Bad disk, cannot format" CASE 255 : ErrMsg$ = "Disk not formatted." CASE ELSE : ErrMsg$ = "Unknown disk error" END SELECT VIEW TEXT (1,1)-(80,25) M$= ErrMsg$ IF Ask THEN M$=M$ + " (A)bort or (R)etry? " ELSE M$=M$+" - Press a key" END IF Xp=(80-LEN(M$)-2)\2 SaveScreen T$ Box 22,Xp,2,LEN(M$)+2,12,3 LOCATE 23,Xp+1 :PRINT M$; IF Ask THEN DO DO : K$ = UCASE$(INKEY$) :LOOP UNTIL LEN(K$) LOOP UNTIL INSTR(CHR$(&H27)+"AR", K$) IF K$ = "R" THEN Error13 = %False ELSE Waitkey END IF RestoreScreen T$ VIEW TEXT (22,8)-(57,22) COLOR 15,3 END FUNCTION '--------------------------------------------------------------------- FUNCTION DosVersion! PUBLIC SHARED ' Get DOS version decimal (e.g. 6.2) '--------------------------------------------------------------------- ! MOV AX, &h3000 ! INT &H21 ! MOV Hi, AH ! MOV Lo, AL DosVersion! = Lo + Hi / 100 END FUNCTION '--------------------------------------------------------------------- SUB DiskInfo (BYVAL Drive, Total&, Free&) PUBLIC SHARED '-------------------------------------------------------------------- LOCAL f,c,s,b Drive = Drive + 1 ' A = 1 / B = 2 ! MOV AX,&H3600 ; AH 36h = Get drive information ! MOV DX, Drive ; drive number ! INT &H21 ; do it ! MOV f, BX ; free clusters ! MOV c, DX ; total number of clusters ! MOV s, AX ; sectors per cluster ! MOV b, CX ; bytes per sector Total& = c * s * b ' bytes total Free& = f * s * b ' bytes available Bytes = b * s ' bytes per cluster Clusters = c ' clusters on disk Sectors = s ' sectors per cluster END SUB '----------------------------------------------- SUB Box (Row, Col, Rows, Cols, Fgc, Bgc) PUBLIC '----------------------------------------------- COLOR Fgc,Bgc LOCATE Row, Col PRINT "Ú" + STRING$(Cols - 1, "Ä") + "¿" LOCATE Row + Rows , Col PRINT "À" + STRING$(Cols - 1, "Ä") + "Ù" FOR i = 1 TO Rows - 1 LOCATE Row + i, Col PRINT "³" + SPACE$(Cols - 1) + "³" NEXT END SUB '----------------------------- SUB SaveScreen (Scrn$) PUBLIC SHARED '----------------------------- IF (pbvScrnCard AND 1) = 0 THEN Address = &HB800 ELSE Address = &HB000 END IF DEF SEG = Address Scrn$ = PEEK$(0,4000) DEF SEG END SUB '-------------------------------- SUB RestoreScreen (Scrn$) PUBLIC SHARED '-------------------------------- IF (pbvScrnCard AND 1) = 0 THEN Address = &HB800 ELSE Address = &HB000 END IF DEF SEG = Address POKE$ 0,Scrn$ DEF SEG END SUB '==== eof ==================================================================