home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / TURBODS / CHECKDIR.LBR / CHECKDIR.MQD / CHECKDIR.MOD
Text File  |  2000-06-30  |  20KB  |  816 lines

  1. MODULE CheckDir;
  2.  
  3. FROM SYSTEM IMPORT ADDRESS, ADR, ALLOCATE, DEALLOCATE, SIZE, TSIZE;
  4.  
  5. FROM TERM1  IMPORT Read, Write, WriteCard, WriteString, WriteLn;
  6.  
  7. IMPORT TERM1, TurboDOS;
  8.  
  9. TYPE BYTE       = CHAR;
  10.  
  11. CONST CPM       = FALSE;
  12.       Debug     = FALSE;
  13.  
  14. TYPE DirFilePtr = POINTER TO RECORD
  15.       FCB:        RECORD
  16.         Drive:    BYTE;
  17.         Name:     ARRAY[0.. 7] OF CHAR;
  18.         Type:     ARRAY[0.. 2] OF CHAR;
  19.         Filler:   ARRAY[1..20] OF CHAR;
  20.         CurRec:   BYTE;
  21.         RanRec:   RECORD
  22.           Low:    CARDINAL;
  23.           High:   BYTE;
  24.         END;
  25.       END;
  26.       EntryNumb:  CARDINAL;
  27.       MaxEntrys:  CARDINAL;
  28.       DirNdx:     [0..3];
  29.       DirBlock:   ARRAY[0..3] OF ARRAY[1..32] OF CHAR;
  30.     END;
  31.  
  32. TYPE FileNamePtr= POINTER TO FileNameDef;
  33.      FileNameDef= RECORD
  34.        User:      BYTE;
  35.        Name:      ARRAY[0..7] OF CHAR;
  36.        Type:      ARRAY[0..2] OF CHAR;
  37.      END;
  38.  
  39.      DirEntryDef= RECORD
  40.        FileName:  FileNameDef;
  41.        Filler:    ARRAY[0..3] OF BYTE;
  42.        SectorGroup:ARRAY[1..8] OF CARDINAL;
  43.      END;
  44.  
  45.      EntryPtr=    POINTER TO EntryDef;
  46.      EntryDef=    RECORD
  47.        FileName:  FileNameDef;
  48.        Size:      CARDINAL;
  49.        Left,
  50.        Right:     EntryPtr;
  51.      END;
  52.  
  53.      ErrNamePtr   = POINTER TO ErrNameDef;
  54.      ErrNameDef   = RECORD
  55.        FileName:    FileNameDef;
  56.        Next:        ErrNamePtr;
  57.      END;
  58.      SecGrpErrors = SET OF (Duplicated, UnMarked);
  59.      SecGrpErrPtr = POINTER TO SecGrpErrDef;
  60.      SecGrpErrDef = RECORD
  61.        SecGrpNumb:  CARDINAL;
  62.        Errors:      SecGrpErrors;
  63.        FileName:    ErrNamePtr;
  64.        Left, Right: SecGrpErrPtr;
  65.      END;
  66.  
  67. VAR BasePage[0000h]: TurboDOS.BasePageDef;
  68.     SysRegs:      TurboDOS.CpuRegDef;
  69.  
  70. VAR SelectedDrive:CARDINAL;
  71.     BlockSize:    CARDINAL;
  72.     DirBlocks:    CARDINAL;
  73.     MaxBlocks:    CARDINAL;
  74.  
  75.     UsedDE,
  76.     UsedSG:       CARDINAL;
  77.  
  78.     SysSecGrpMap: POINTER TO ARRAY[0..4095] OF BITSET;
  79.     SecGrpMap:    POINTER TO ARRAY[0..4095] OF BITSET;
  80.  
  81.     SGEHead,
  82.     CurrSGE:      SecGrpErrPtr;
  83.  
  84.     EntryHead,
  85.     CurrEntry:    EntryPtr;
  86.  
  87.     CurrUser:     CARDINAL;
  88.     DispCount:    CARDINAL;
  89.  
  90. VAR DirFile:      DirFilePtr;
  91.     DirEntry:     DirEntryDef;
  92.  
  93. PROCEDURE FillChar(PData : ADDRESS;
  94.                    Len   : CARDINAL;
  95.                    ch    : CHAR);
  96.  
  97. VAR c:            CARDINAL;
  98.     Data:         POINTER TO CHAR;
  99.  
  100. BEGIN (* FillChar *)
  101.  
  102.   Data := PData;
  103.  
  104.   FOR c := 1 TO Len DO
  105.       Data^ := ch;
  106.       INC(Data);
  107.   END;
  108.  
  109. END FillChar;
  110.  
  111. PROCEDURE Move(To, From : ADDRESS;
  112.                Length   : CARDINAL);
  113.  
  114. TYPE ChrPtr     = POINTER TO CHAR;
  115.  
  116. VAR Aop, Bop:     ChrPtr;
  117.     Count:        CARDINAL;
  118.  
  119. BEGIN (* Move *)
  120.  
  121.   Aop := To;
  122.   Bop := From;
  123.  
  124.   FOR Count := 1 TO Length DO
  125.       Aop^ := Bop^;
  126.       INC(Aop);
  127.       INC(Bop);
  128.   END;
  129.  
  130. END Move;
  131.  
  132. PROCEDURE EndJob;
  133.  
  134. BEGIN (* EndJob *);
  135.  
  136.   HALT;
  137.  
  138. END EndJob;
  139.  
  140. PROCEDURE DisplayMessage(Message : ARRAY OF CHAR);
  141.  
  142. BEGIN (* DisplayMessage *)
  143.  
  144.   IF Debug
  145.      THEN WriteString(Message); WriteLn;
  146.   END;
  147.  
  148. END DisplayMessage;
  149.  
  150. PROCEDURE GetDriveToCheck() : CARDINAL;
  151.  
  152. VAR CDrive:       CHAR;
  153.     c:            CARDINAL;
  154.  
  155.   PROCEDURE UserInpDrive() : CARDINAL;
  156.  
  157.   VAR Drive:      CARDINAL;
  158.  
  159.   BEGIN (* UserInpDrive *)
  160.  
  161.     WriteLn;
  162.     WriteString('Enter the drive to check [A -> P] ');
  163.  
  164.     LOOP Read(CDrive);
  165.          IF       CDrive = ' '
  166.             THEN EndJob;
  167.             ELSE IF (CAP(CDrive) >= 'A') AND
  168.                     (CAP(CDrive) <= 'P')
  169.                     THEN Drive := ORD(CAP(CDrive)) - ORD('A');
  170.                          EXIT;
  171.                     ELSE  Write(CHR(07h));
  172.                  END;
  173.          END;
  174.     END;
  175.  
  176.     Write(CDrive); WriteLn;
  177.  
  178.     RETURN Drive;
  179.  
  180.   END UserInpDrive;
  181.  
  182.   PROCEDURE CmdLineDrive() : CARDINAL;
  183.  
  184.   BEGIN (* CmdLineDrive *)
  185.  
  186.     WITH BasePage.SysBuffer.CommandLine DO
  187.          c := 0;
  188.          WHILE (Data[c] # 0C)     AND
  189.                (c <= ORD(Length)) DO
  190.                CDrive := Data[c];
  191.                IF (CAP(CDrive) >= 'A') AND
  192.                   (CAP(CDrive) <= 'P')
  193.                   THEN RETURN ORD(CAP(CDrive)) - ORD('A');
  194.                   ELSE INC(c);
  195.                END;
  196.          END;
  197.          RETURN UserInpDrive();
  198.     END;
  199.  
  200.   END CmdLineDrive;
  201.  
  202. BEGIN (* GetDriveToCheck *)
  203.  
  204.   IF ORD(BasePage.SysBuffer.CommandLine.Length) > 0
  205.      THEN RETURN CmdLineDrive();
  206.      ELSE RETURN UserInpDrive();
  207.   END;
  208.  
  209. END GetDriveToCheck;
  210.  
  211.  
  212. PROCEDURE OpenDir(VAR DirFile : DirFilePtr;
  213.                       DirDrive: CARDINAL)   : BOOLEAN;
  214.  
  215. BEGIN (* OpenDir *)
  216.  
  217.   NEW(DirFile);
  218.  
  219.   FillChar(ADDRESS(DirFile), SIZE(DirFile^), CHR(0));
  220.  
  221.   WITH DirFile^ DO
  222.        WITH SysRegs DO
  223.             RegC := CHR(19);
  224.             RegE := CHR(DirDrive);
  225.             TurboDOS.TBDOS(SysRegs);
  226.             DirBlocks := ORD(RegC);
  227.             MaxBlocks := RegHL;
  228.             BlockSize := ORD(BITSET(ORD(AF)) * {0..2});
  229.        END;
  230.        IF       BlockSize = 3 THEN BlockSize :=  32;
  231.           ELSIF BlockSize = 4 THEN BlockSize :=  64;
  232.           ELSIF BlockSize = 5 THEN BlockSize := 128;
  233.           ELSIF BlockSize = 6 THEN BlockSize := 256;
  234.           ELSIF BlockSize = 7 THEN BlockSize := 512;
  235.        END;
  236.        MaxEntrys := DirBlocks * BlockSize;
  237.        FCB.Drive := CHR(DirDrive + 1);
  238.        FCB.Name := '$       ';
  239.        FCB.Type := 'DIR';
  240.        WITH SysRegs DO
  241.             RegBC := 15;
  242.             RegDE := ADR(FCB);
  243.             TurboDOS.CBDOS(SysRegs);
  244.             RegBC := 26;
  245.             RegDE := ADR(DirBlock);
  246.             TurboDOS.CBDOS(SysRegs);
  247.             RegBC := 20;
  248.             RegDE := ADR(FCB);
  249.             TurboDOS.CBDOS(SysRegs);
  250.        END;
  251.        BlockSize := BlockSize * 32;
  252.        DirNdx := 0;
  253.   END;
  254.  
  255.   RETURN TRUE;
  256.  
  257. END OpenDir;
  258.  
  259. PROCEDURE CloseDir(VAR DirFile : DirFilePtr) : BOOLEAN;
  260.  
  261. BEGIN (* CloseDir *)
  262.  
  263.   WITH DirFile^ DO
  264.        WITH SysRegs DO
  265.             RegBC := 16;
  266.             RegDE := ADR(FCB);
  267.             TurboDOS.CBDOS(SysRegs);
  268.        END;
  269.   END;
  270.  
  271.   RETURN TRUE;
  272.  
  273. END CloseDir;
  274.  
  275. PROCEDURE GetDirEntry(VAR DirFile      : DirFilePtr;
  276.                           DirEntryNumb : CARDINAL;
  277.                           DirEntry     : ADDRESS)  : BOOLEAN;
  278.  
  279. VAR RecNo:        CARDINAL;
  280.  
  281. BEGIN (* GetDirEntry *)
  282.  
  283.   IF DirEntryNumb < DirFile^.MaxEntrys
  284.      THEN WITH DirFile^ DO
  285.                RecNo  := DirEntryNumb DIV 4;
  286.                IF RecNo # FCB.RanRec.Low
  287.                   THEN FCB.RanRec.Low := RecNo;
  288.                        WITH SysRegs DO
  289.                             RegBC := 26;
  290.                             RegDE := ADR(DirBlock);
  291.                             TurboDOS.CBDOS(SysRegs);
  292.                             RegBC := 33;
  293.                             RegDE := ADR(FCB);
  294.                             TurboDOS.CBDOS(SysRegs);
  295.                        END;
  296.                END;
  297.                DirNdx := DirEntryNumb MOD 4;
  298.                Move(DirEntry, ADR(DirBlock[DirNdx]), 32);
  299.                EntryNumb := DirEntryNumb;
  300.           END;
  301.           RETURN TRUE;
  302.      ELSE RETURN FALSE;
  303.   END;
  304.  
  305. END GetDirEntry;
  306.  
  307. PROCEDURE GetFirstDirEntry(VAR DirFile  : DirFilePtr;
  308.                                DirEntry : ADDRESS)  : BOOLEAN;
  309.  
  310. BEGIN (* GetFirstDirEntry *)
  311.  
  312.   RETURN GetDirEntry(DirFile, 0, DirEntry);
  313.  
  314. END GetFirstDirEntry;
  315.  
  316. PROCEDURE GetNextDirEntry(VAR DirFile  : DirFilePtr;
  317.                               DirEntry : ADDRESS)  : BOOLEAN;
  318.  
  319. BEGIN (* GetNextDirEntry *)
  320.  
  321.   RETURN GetDirEntry(DirFile, DirFile^.EntryNumb + 1, DirEntry);
  322.  
  323. END GetNextDirEntry;
  324.  
  325. PROCEDURE BuildSysSecGrpMap;
  326.  
  327. VAR c, c1, c2:    CARDINAL;
  328.     AllocMap:     ARRAY[1..15] OF BITSET;
  329.  
  330. BEGIN (* BuildSysSecGrpMap *)
  331.  
  332.   DisplayMessage('Entering BuildSysSecGrpMap');
  333.  
  334.   FOR c := 0 TO 4095 DO
  335.      SysSecGrpMap^[c] := {};
  336.         SecGrpMap^[c] := {};
  337.   END;
  338.  
  339.   c1 := MaxBlocks DIV 16;
  340.  
  341.   IF MaxBlocks # (c1 * 16)
  342.      THEN INC(c1);
  343.   END;
  344.  
  345.   FOR c := 0 TO (c1 - 1) DO
  346.      SysSecGrpMap^[c] := {};
  347.         SecGrpMap^[c] := {};
  348.   END;
  349.  
  350.   IF GetFirstDirEntry(DirFile, ADR(DirEntry))
  351.      THEN Move(ADR(AllocMap[ 1]), ADR(DirEntry.FileName.Name), 14);
  352.           Move(ADR(AllocMap[ 8]), ADR(DirEntry.SectorGroup), 16);
  353.           c2 := 15; (* Force us by the Volume Label Entry *)
  354.           FOR c := 0 TO (c1 - 1) DO
  355.               INC(c2);
  356.               IF c2 > 15
  357.                  THEN IF GetNextDirEntry(DirFile, ADR(DirEntry))
  358.                          THEN Move(ADR(AllocMap[ 1]), ADR(DirEntry.FileName.Name), 14);
  359.                               Move(ADR(AllocMap[ 8]), ADR(DirEntry.SectorGroup), 16);
  360.                          ELSE FillChar(ADR(AllocMap), SIZE(AllocMap), CHR(0));
  361.                       END;
  362.                       c2 := 1;
  363.               END;
  364.               SysSecGrpMap^[c] := AllocMap[c2];
  365.           END;
  366.   END;
  367.  
  368.   DisplayMessage('Leaving BuildSysSecGrpMap');
  369.  
  370. END BuildSysSecGrpMap;
  371.  
  372. (*
  373. PROCEDURE CompareEntry(VAR AParm, BParm : EntryPtr;
  374.                            Length       : CARDINAL) : INTEGER;
  375.  
  376. VAR AOP, BOP:     POINTER TO CHAR;
  377.     c:            CARDINAL;
  378.  
  379. BEGIN (* CompareEntry *)
  380.  
  381.   AOP := ADDRESS(AParm);
  382.   BOP := ADDRESS(BParm);
  383.  
  384.   c := 0;
  385.  
  386.   WHILE c < Length DO
  387.         IF       AOP^ < BOP^ THEN RETURN -1;
  388.            ELSIF AOP^ > BOP^ THEN RETURN  1;
  389.            ELSE INC(AOP);
  390.                 INC(BOP);
  391.                 INC(c);
  392.         END;
  393.   END;
  394.  
  395.   RETURN 0;
  396.  
  397. END CompareEntry;
  398.  
  399. PROCEDURE InsertEntry(VAR Base, Test : EntryPtr);
  400.  
  401. BEGIN (* InsertEntry *)
  402.  
  403.   IF Base = NIL
  404.      THEN Base := Test;
  405.      ELSE CASE CompareEntry(Base, Test, 1 + 8 + 3) OF
  406.             -1 : InsertEntry(Base^.Right, Test);
  407.           |  0 : Base^.Size := Base^.Size + Test^.Size;
  408.                  DISPOSE(Test);
  409.           |  1 : InsertEntry(Base^.Left, Test);
  410.           END;
  411.   END;
  412.  
  413. END InsertEntry;
  414.  
  415. PROCEDURE ListEntrys(VAR Entry : EntryPtr);
  416.  
  417. BEGIN (* ListEntrys *)
  418.  
  419.   IF Entry # NIL
  420.      THEN ListEntrys(Entry^.Left);
  421.           WITH Entry^.FileName DO
  422.                IF CurrUser # ORD(User)
  423.                   THEN WriteLn;
  424.                        CurrUser  := ORD(User);
  425.                        DispCount := 0;
  426.                END;
  427.                IF DispCount = 3
  428.                   THEN WriteLn;
  429.                        DispCount := 0;
  430.                END;
  431.                WriteCard(ORD(User), 2); Write(':');
  432.                WriteString(Name);       Write('.');
  433.                WriteString(Type);
  434.                WriteCard(Entry^.Size * BlockSize, 6);
  435.                WriteString('k   ');
  436.                INC(DispCount);
  437.           END;
  438.           ListEntrys(Entry^.Right);
  439.   END;
  440.  
  441. END ListEntrys;
  442. *)
  443.  
  444. PROCEDURE SortSecGrpErr(VAR Base, Temp : SecGrpErrPtr);
  445.  
  446. BEGIN (* SortSecGrpErr *)
  447.  
  448.   IF Base = NIL
  449.      THEN Base := Temp;
  450.      ELSIF Base^.SecGrpNumb < Temp^.SecGrpNumb
  451.            THEN SortSecGrpErr(Base^.Right, Temp);
  452.      ELSIF Base^.SecGrpNumb > Temp^.SecGrpNumb
  453.            THEN SortSecGrpErr(Base^.Left, Temp);
  454.      ELSE Base^.Errors := Base^.Errors + Temp^.Errors;
  455.           DISPOSE(Temp);
  456.   END;
  457.  
  458. END SortSecGrpErr;
  459.  
  460. PROCEDURE ListSecGrpErrors(VAR Entry : SecGrpErrPtr);
  461.  
  462. VAR Count:        CARDINAL;
  463.     TempName:     ErrNamePtr;
  464.  
  465. BEGIN (* ListSecGrpErrors *)
  466.  
  467.   IF Entry # NIL
  468.      THEN ListSecGrpErrors(Entry^.Left);
  469.           WriteCard(Entry^.SecGrpNumb, 5);
  470.           IF Duplicated IN Entry^.Errors
  471.              THEN WriteString(' Duplicated');
  472.           END;
  473.           IF UnMarked IN Entry^.Errors
  474.              THEN WriteString(' UnMarked');
  475.           END;
  476.           IF Entry^.FileName = NIL
  477.              THEN WriteLn;
  478.              ELSE Count := 1;
  479.                   TempName := Entry^.FileName;
  480.                   WHILE TempName # NIL DO
  481.                         WITH TempName^.FileName DO
  482.                              WriteCard(ORD(User), 3); Write(':');
  483.                              WriteString(Name);       Write('.');
  484.                              WriteString(Type);
  485.                         END;
  486.                         INC(Count);
  487.                         IF Count = 4
  488.                            THEN WriteLn;
  489.                           WriteString('     ');
  490.                                 Count := 0;
  491.                         END;
  492.                         TempName := TempName^.Next;
  493.                   END;
  494.                   IF Count # 0
  495.                      THEN WriteLn;
  496.                   END;
  497.           END;
  498.           ListSecGrpErrors(Entry^.Right);
  499.   END;
  500.  
  501. END ListSecGrpErrors;
  502.  
  503. PROCEDURE ProcessSecGrpErrors;
  504.  
  505.   PROCEDURE ProcessDirEntry(VAR DirEntry : DirEntryDef);
  506.  
  507.   VAR c:    CARDINAL;
  508.  
  509.     PROCEDURE CheckSectorGroup(VAR SectorGroup : CARDINAL);
  510.  
  511.     VAR SGETemp:    SecGrpErrPtr;
  512.         NamePtr,
  513.         TempName:    ErrNamePtr;
  514.  
  515.       PROCEDURE ChkSecGrp(VAR Base : SecGrpErrPtr;
  516.                           VAR SGN  : CARDINAL) : SecGrpErrPtr;
  517.  
  518.       BEGIN (* ChkSecGrp *)
  519.  
  520.         IF Base = NIL
  521.            THEN RETURN Base;
  522.            ELSIF Base^.SecGrpNumb < SGN
  523.                  THEN RETURN ChkSecGrp(Base^.Right, SGN);
  524.            ELSIF Base^.SecGrpNumb > SGN
  525.                  THEN RETURN ChkSecGrp(Base^.Left, SGN);
  526.                  ELSE RETURN Base;
  527.         END;
  528.  
  529.       END ChkSecGrp;
  530.  
  531.     BEGIN (* CheckSectorGroup *)
  532.  
  533.       SGETemp := ChkSecGrp(SGEHead, SectorGroup);
  534.  
  535.       IF SGETemp # NIL
  536.          THEN NEW(NamePtr);
  537.               NamePtr^.FileName := DirEntry.FileName;
  538.               NamePtr^.Next     := NIL;
  539.               IF SGETemp^.FileName = NIL
  540.                  THEN SGETemp^.FileName := NamePtr;
  541.                  ELSE TempName := SGETemp^.FileName;
  542.                       WHILE TempName^.Next # NIL DO
  543.                             TempName := TempName^.Next;
  544.                       END;
  545.                       TempName^.Next := NamePtr;
  546.               END;
  547.       END;
  548.  
  549.     END CheckSectorGroup;
  550.  
  551.   BEGIN (* ProcessDirEntry *)
  552.  
  553.     WITH DirEntry DO
  554.          IF FileName.User < CHR(32)
  555.             THEN c := 1;
  556.                  WHILE (c < 9)              AND
  557.                        (SectorGroup[c] > 0) DO
  558.                        CheckSectorGroup(SectorGroup[c]);
  559.                        INC(c);
  560.                  END;
  561.          END;
  562.     END;
  563.  
  564.   END ProcessDirEntry;
  565.  
  566. BEGIN (* ProcessSecGrpErrors *)
  567.  
  568.   IF GetFirstDirEntry(DirFile, ADR(DirEntry))
  569.      THEN REPEAT ProcessDirEntry(DirEntry);
  570.           UNTIL  NOT GetNextDirEntry(DirFile, ADR(DirEntry));
  571.   END;
  572.  
  573.   ListSecGrpErrors(SGEHead);
  574.  
  575. END ProcessSecGrpErrors;
  576.  
  577. PROCEDURE CheckSecGrpAllocation;
  578.  
  579. VAR Plus, Minus:  CARDINAL;
  580.     c, cmax:      CARDINAL;
  581.  
  582.   PROCEDURE CheckBits(VAR a, b  : BITSET;
  583.                           COUNT : CARDINAL);
  584.  
  585.   VAR c1:    CARDINAL;
  586.  
  587.     PROCEDURE ReportType1;
  588.  
  589.     BEGIN (* ReportType1 *)
  590.  
  591.       WriteString('Sector Group');
  592.       WriteCard((c * 16) + c1 + 1, 6);
  593.       WriteString(' Allocated but not within any extent');
  594.       WriteLn;
  595.  
  596.       INC(Plus);
  597.  
  598.     END ReportType1;
  599.  
  600.     PROCEDURE ReportType2;
  601.  
  602.     VAR Temp:       SecGrpErrPtr;
  603.  
  604.     BEGIN (* ReportType2 *)
  605.  
  606.       WriteString('Sector Group');
  607.       WriteCard((c * 16) + c1, 5);
  608.       WriteString(' within an extent but not Allocated');
  609.       WriteLn;
  610.  
  611.       INC(Minus);
  612.  
  613.       NEW(Temp);
  614.  
  615.       WITH Temp^ DO
  616.          SecGrpNumb := (c * 16) + c1;
  617.          Errors     := SecGrpErrors{UnMarked};
  618.          FileName   := NIL;
  619.          Left       := NIL;
  620.          Right      := NIL;
  621.       END;
  622.  
  623.       SortSecGrpErr(SGEHead, Temp);
  624.  
  625.     END ReportType2;
  626.  
  627.   BEGIN (* CheckBits *)
  628.  
  629.      FOR c1 := 0 TO COUNT DO
  630.          IF c1 IN a
  631.             THEN  IF NOT (c1 IN b)
  632.                      THEN ReportType1;
  633.                   END;
  634.             ELSIF c1 IN b
  635.                   THEN ReportType2;
  636.          END;
  637.      END;
  638.  
  639.   END CheckBits;
  640.  
  641. BEGIN (* CheckSecGrpAllocation *)
  642.  
  643.   Plus := 0;
  644.   Minus := 0;
  645.  
  646.   c := 0; cmax := MaxBlocks DIV 16;
  647.  
  648.   LOOP IF c < cmax (* This will keep it relative to zero *)
  649.           THEN IF CARDINAL(SysSecGrpMap^[c]) # CARDINAL(SecGrpMap^[c])
  650.                   THEN CheckBits(SysSecGrpMap^[c], SecGrpMap^[c], 15);
  651.                END;
  652.                INC(c);
  653.           ELSE EXIT;
  654.        END;
  655.   END;
  656.  
  657.   IF (MaxBlocks MOD 16) # 0 (* This will pick up any dangling bits *)
  658.      THEN CheckBits(SysSecGrpMap^[c], SecGrpMap^[c], ((MaxBlocks MOD 16) - 1));
  659.   END;
  660.  
  661.   IF Plus > 0
  662.      THEN WriteString('Disk will GAIN');
  663.           WriteCard(Plus, 6);
  664.           WriteString(' Sector Groups');
  665.           WriteLn;
  666.   END;
  667.  
  668.   IF Minus > 0
  669.      THEN WriteString('Disk will LOSE');
  670.           WriteCard(Minus, 6);
  671.           WriteString(' Sector Groups');
  672.           WriteLn;
  673.   END;
  674.   
  675.  
  676. END CheckSecGrpAllocation;
  677.  
  678. PROCEDURE ProcessDirEntry(DirEntry : DirEntryDef);
  679.  
  680. VAR c,
  681.     SecGrpNdx,
  682.     SecGrpBit:    CARDINAL;
  683.     Test:         EntryPtr;
  684.  
  685.   PROCEDURE ReportDuplicated;
  686.  
  687.   VAR Temp:       SecGrpErrPtr;
  688.  
  689.   BEGIN (* ReportDuplicated *)
  690.  
  691.     WITH DirEntry DO
  692.          WriteString('Duplicate Sector Group Found');
  693.          WriteCard(SectorGroup[c],6);
  694.          WriteCard(ORD(FileName.User), 3);
  695.          WriteString(':');
  696.          WriteString(FileName.Name);
  697.          WriteString('.');
  698.          WriteString(FileName.Type);
  699.          WriteLn;
  700.     END;
  701.  
  702.     NEW(Temp);
  703.  
  704.     WITH Temp^ DO
  705.        SecGrpNumb := DirEntry.SectorGroup[c];
  706.        Errors     := SecGrpErrors{Duplicated};
  707.        FileName   := NIL;
  708.        Left       := NIL;
  709.        Right      := NIL;
  710.     END;
  711.  
  712.     SortSecGrpErr(SGEHead, Temp);
  713.  
  714.   END ReportDuplicated;
  715.  
  716. BEGIN (* ProcessDirEntry *)
  717.  
  718.   DisplayMessage('Entering ProcessDirEntry');
  719.  
  720.   IF ORD(DirEntry.FileName.User) < 32
  721.      THEN WITH DirEntry DO
  722. (*
  723.                INC(UsedDE);
  724.                NEW(Test);
  725.                WITH Test^ DO
  726.                     FileName := DirEntry.FileName;
  727.                     Size := 0;
  728.                     Left := NIL;
  729.                     Right := NIL;
  730.                END;
  731. *)
  732.                c := 1;
  733.                WHILE (c <= 8)             AND
  734.                      (SectorGroup[c] > 0) DO
  735.                      INC(Test^.Size);
  736.                      SecGrpNdx := SectorGroup[c] DIV 16;
  737.                      SecGrpBit := SectorGroup[c] MOD 16;
  738.                      IF SecGrpBit IN SecGrpMap^[SecGrpNdx]
  739.                         THEN ReportDuplicated;
  740.                         ELSE INCL(SecGrpMap^[SecGrpNdx], SecGrpBit);
  741.                      END;
  742.                      INC(UsedSG);
  743.                      INC(c);
  744.                END;
  745. (*
  746.                InsertEntry(EntryHead, Test);
  747. *)
  748.           END;
  749.   END;
  750.  
  751.   DisplayMessage('Leaving ProcessDirEntry');
  752.  
  753. END ProcessDirEntry;
  754.  
  755. PROCEDURE DoProcess;
  756.  
  757. VAR c, c1, c2,
  758.     cmax:         CARDINAL;
  759.  
  760. BEGIN (* DoProcess *)
  761.  
  762.   DisplayMessage('Entering DoProcess');
  763.  
  764.   ALLOCATE(SysSecGrpMap, MaxBlocks + DirBlocks + 1);
  765.   ALLOCATE(   SecGrpMap, MaxBlocks + DirBlocks + 1);
  766.  
  767.   BuildSysSecGrpMap;
  768.  
  769.   EntryHead := NIL;
  770.   SGEHead   := NIL;
  771.  
  772.   FOR c := 0 TO (DirBlocks - 1) DO
  773.       INCL(SecGrpMap^[(c DIV 16)], (c MOD 16));
  774.   END;
  775.  
  776.   IF GetFirstDirEntry(DirFile, ADR(DirEntry))
  777.      THEN REPEAT ProcessDirEntry(DirEntry);
  778.           UNTIL  NOT GetNextDirEntry(DirFile, ADR(DirEntry));
  779.   END;
  780.  
  781.   CheckSecGrpAllocation;
  782.  
  783. (*
  784.   IF EntryHead # NIL
  785.      THEN CurrUser  := 32;
  786.           DispCount := 0;
  787.           BlockSize := BlockSize DIV 1024;
  788.           ListEntrys(EntryHead);
  789.   END;
  790. *)
  791.  
  792.   IF SGEHead = NIL
  793.      THEN WriteString('Disk Allocation Map, and Directory are OK');
  794.           WriteLn;
  795.      ELSE ProcessSecGrpErrors;
  796.   END;
  797.  
  798.   WriteLn;
  799.  
  800.   DisplayMessage('Leaving DoProcess');
  801.  
  802. END DoProcess;
  803.  
  804. BEGIN (* CheckDir *)
  805.  
  806.   SelectedDrive := GetDriveToCheck();
  807.  
  808.   IF OpenDir(DirFile, SelectedDrive)
  809.      THEN DoProcess;
  810.           IF NOT CloseDir(DirFile)
  811.              THEN HALT;
  812.           END;
  813.   END;
  814.  
  815. END CheckDir.
  816.