home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / LU86_2.ZIP / LU86-2.PAS
Encoding:
Pascal/Delphi Source File  |  1986-11-08  |  19.7 KB  |  768 lines

  1. {$C-}
  2. {     Compile with RawTurbo using mAximum Stack of 800h paragraphs     }
  3. PROGRAM Lu86;
  4. CONST
  5.     Version        = 'Lu86 v 1.06';
  6.     CopyRight      = '  (c)1984 by Charlie Godet-Ceraolo';
  7.     Active         = $00;
  8.     Colon          = ':';
  9.     CRMsg          = ' (<CR> exits) : ';
  10.     Deleted        = $FE;
  11.     LibExt         = '.LBR';
  12.     LinesPerScreen = 20;
  13.     NoFileMsg      = ' not found';
  14.     NoLibMsg       = 'No Library open';
  15.     NumAcross      = 4;
  16.     Period         = '.';
  17.     QMark          = '?';
  18.     ROMsg          = 'Library is READ ONLY';
  19.     SectorSize     = 128;
  20.     SlotsPerSect   =   4;
  21.     Space          = ' ';
  22.     Star           = '*';
  23.     UnUsed         = $FF;
  24.     ZeroCRC        =  0;
  25.  
  26. TYPE
  27.     AnyFile      = FILE;
  28.     BdosRegs     = RECORD
  29.                      AX,BX,CX,DX,BP,
  30.                      SI,DI,DS,ES,Flags : INTEGER;
  31.                    END;
  32.     LineType     = STRING[80];
  33.     FNamType     = STRING[20];
  34.     NameType     = ARRAY[1..11] OF CHAR;
  35.     DirInfoRec   = RECORD
  36.                       MaxEnts   : INTEGER;
  37.                       HiSlotNum : INTEGER;
  38.                       LiveEnts  : INTEGER;
  39.                    END;
  40.     DirEntryType = RECORD
  41.                       Status : BYTE;
  42.                       Fname  : NameType;
  43.                       Start  : INTEGER;
  44.                       Count  : INTEGER;
  45.                       CRC    : INTEGER;
  46.                       Fill   : ARRAY[0..13] OF BYTE;
  47.                    END;
  48.     DIRType      = ARRAY[0..1000] OF DirEntryType;
  49.     DirPtr       = ^DIRType;
  50.     DirSect      = ARRAY[0..3] OF DirEntryType;
  51.     ResultType   = (LT,SAME,GT);
  52.  
  53. VAR
  54.     Ch         : CHAR;
  55.     DIR        : DirPtr;
  56.     DirInfo    : DirInfoRec;
  57.     Heap       : ^INTEGER;
  58.     LibChanged : BOOLEAN;
  59.     LibFile    : AnyFile;
  60.     LibName    : FNamType;
  61.     LibOpen    : BOOLEAN;
  62.     LibRO      : BOOLEAN;
  63.  
  64. PROCEDURE Initialize;
  65. BEGIN { Initialize }
  66.     DIR     := NIL;
  67.     LibName := '';
  68.     LibOpen := FALSE;
  69.     LibChanged := FALSE;
  70.     WITH DirInfo DO BEGIN
  71.         MaxEnts   := 0;
  72.         HiSlotNum := 0;
  73.     END;
  74. END; { Initialize }
  75.  
  76. PROCEDURE UpString(VAR S : FNamType);
  77. VAR
  78.     X : BYTE;
  79.  
  80. BEGIN { UpString }
  81.     FOR X := 1 TO LENGTH(S) DO
  82.         IF S[X] IN ['a'..'z'] THEN S[X] := CHR(ORD(S[X])-32);
  83. END; { UpString }
  84.  
  85. PROCEDURE GetFileName( Msg : LineType; VAR S : FNamType );
  86. BEGIN { GetFileName }
  87.     WRITE(Msg+CRMsg);
  88.     READLN(S);
  89.     UpString(S);
  90. END; { GetFileName }
  91.  
  92. FUNCTION IsWild( S : FNamType ) : BOOLEAN;
  93. BEGIN { IsWild }
  94.     IsWild := ( (POS(QMark,S) <> 0 ) OR (POS(Star,S) <> 0) )
  95. END; { IsWild }
  96.  
  97. FUNCTION GetDirSize(VAR NumSlots,NumSects : INTEGER; MinSlots : INTEGER) : BOOLEAN;
  98. LABEL 99;
  99. VAR
  100.     Code     : INTEGER;
  101.     S        : STRING[20];
  102.  
  103. BEGIN { GetDirSize }
  104.     GetDirSize := FALSE;
  105.     WRITE('Number of Slots in New Library'+CRMsg);
  106.     READLN(S);
  107.     IF S <> '' THEN  BEGIN
  108.         VAL(S,NumSlots,Code);
  109.         IF Code <> 0 THEN GOTO 99;
  110.         NumSlots := NumSlots + 1;  { for the Directory }
  111.         IF NumSlots < MinSlots THEN NumSlots := MinSlots;
  112.         NumSects := NumSlots DIV SlotsPerSect;
  113.         IF NumSlots MOD SlotsPerSect <> 0 THEN NumSects := NumSects + 1;
  114.         NumSlots := NumSects * SlotsPerSect;
  115.         WRITELN('New Library has  ',NumSlots,' slots');
  116.         GetDirSize := TRUE;
  117.     END;
  118. 99:
  119. END; { GetDirSize }
  120.  
  121. FUNCTION Compare(VAR A,B; Size : INTEGER) : ResultType;
  122. TYPE
  123.     Any = ARRAY[0..100] OF CHAR;
  124.  
  125. VAR
  126.     A1    : Any ABSOLUTE A;
  127.     B1    : Any ABSOLUTE B;
  128.     Equal : BOOLEAN;
  129.     X     : INTEGER;
  130.  
  131. BEGIN { Compare }
  132.     Compare := SAME;
  133.     Equal   := TRUE;
  134.     X       := 0;
  135.     WHILE Equal AND (X < Size) DO BEGIN
  136.          IF A1[X] <> QMark THEN Equal := (A1[X] = B1[X]);
  137.          X := X + 1;
  138.     END;
  139.     X := X - 1;
  140.     IF NOT Equal THEN IF (A1[X] < B1[X]) THEN Compare := LT
  141.     ELSE IF (A1[X] > B1[X]) THEN Compare := GT;
  142. END; { Compare }
  143.  
  144. PROCEDURE PrintFileName(D : DirEntryType);
  145. VAR
  146.     X : INTEGER;
  147.  
  148. BEGIN { PrintFileName }
  149.     FOR X := 1 TO 8 DO WRITE(D.FName[X]);
  150.     WRITE(Period);
  151.     FOR X := 9 TO 11 DO WRITE(D.FName[X]);
  152. END; { PrintFileName }
  153.  
  154. PROCEDURE ListNames;
  155. VAR
  156.     X     : BYTE;
  157.     Items : BYTE;
  158.     I     : INTEGER;
  159.  
  160. PROCEDURE Pause;
  161. VAR
  162.     Ch : CHAR;
  163.  
  164. BEGIN { Pause }
  165.     WRITE('[More..]');
  166.     READ(KBD,Ch);
  167. END; { Pause }
  168.  
  169. BEGIN { ListNames }
  170.     Items := 0;
  171.     WRITELN;
  172.     WITH DirInfo DO BEGIN
  173.         WRITE(LibName,': Max ',MaxEnts);
  174.         WRITE(', Free ', MaxEnts - LiveEnts);
  175.     END;
  176.     WRITELN; WRITELN;
  177.     FOR I := 1 TO DirInfo.HiSlotNum DO WITH DIR^[I] DO BEGIN
  178.         IF Status = Active THEN BEGIN
  179.             Items := Items + 1;
  180.             PrintFileName(DIR^[I]);
  181.             WRITE((Count DIV 8)+1:4,'k');
  182.         IF Items MOD NumAcross = 0 THEN BEGIN
  183.                 WRITELN;
  184.                 IF Items MOD (NumAcross * LinesPerScreen) = 0 THEN Pause;
  185.             END
  186.             ELSE WRITE(' |');
  187.         END;
  188.     END;
  189.     WRITELN; WRITELN;
  190. END; { ListNames }
  191.  
  192. PROCEDURE ReadDir;
  193. VAR
  194.     DirBuf   : DirSect;
  195.     DirSects : INTEGER;
  196.     X,Y      : INTEGER;
  197.  
  198. FUNCTION IsReadOnly(VAR F : AnyFile) : BOOLEAN;
  199. TYPE
  200.     FibType = ARRAY[0..48] OF BYTE;
  201. VAR
  202.     P : ^FibType;
  203.  
  204. BEGIN { IsReadOnly }
  205.     P := ADDR(F);
  206.     IsReadOnly := ( (P^[21] AND $80) <> 0 );
  207. END; { IsReadOnly }
  208.  
  209. BEGIN { ReadDir }
  210.     BLOCKREAD(LibFile,DirBuf,1);
  211.     DirSects := DirBuf[0].Count;
  212.     GETMEM(DIR,DirSects * SectorSize);
  213.     WITH DirInfo DO BEGIN
  214.         LiveEnts := 0;
  215.         MaxEnts  := (DirSects * SlotsPerSect);
  216.         HiSlotNum := MaxEnts - 1;
  217.         LibRO    := IsReadOnly(LibFile);
  218.     END;
  219.     SEEK(LibFile,0);
  220.     BLOCKREAD(LibFile,DIR^,DirSects);
  221.     FOR X := 0 TO DirInfo.HiSlotNum DO WITH DirInfo DO BEGIN
  222.         IF DIR^[X].Status = Active THEN LiveEnts := LiveEnts + 1;
  223.     END;
  224. END; { ReadDir }
  225.  
  226. PROCEDURE MakeName(S : FNamType; VAR N : NameType);
  227. VAR
  228.    State : (Moving, Delimiter, WildCard, EndString);
  229.    X,Y   : BYTE;
  230.  
  231. PROCEDURE DoExtension(StartinString : BYTE);
  232. BEGIN { DoExtension }
  233.     State := Moving;
  234.     X     := StartinString;
  235.     Y     := 9;
  236.     WHILE State = Moving DO BEGIN
  237.         IF X > LENGTH(S) THEN State := EndString
  238.         ELSE IF S[X] = Star THEN State := WildCard
  239.         ELSE BEGIN
  240.             N[Y] := S[X];
  241.             X    := X + 1;
  242.             Y    := Y + 1;
  243.         END;
  244.     END; { While }
  245.     IF State = WildCard THEN FOR X := Y TO 11 DO N[X] := QMark
  246. END; { DoExtension }
  247.  
  248. BEGIN { MakeName }
  249.     FILLCHAR(N,SIZEOF(N),Space);
  250.     UpString(S);
  251.     X := POS(Colon,S);
  252.     IF X <> 0 THEN DELETE(S,1,X);
  253.     State := Moving;
  254.     X     := 1;
  255.     WHILE State = Moving DO BEGIN
  256.         IF X > LENGTH(S) THEN State := EndString
  257.         ELSE IF S[X] = Period THEN State := Delimiter
  258.         ELSE IF S[X] = Star THEN State := WildCard
  259.         ELSE BEGIN
  260.             N[X] := S[X];
  261.             X    := X + 1;
  262.         END;
  263.     END; { While }
  264.     IF State = Delimiter THEN DoExtension(X+1)
  265.     ELSE IF State = WildCard THEN BEGIN
  266.              FOR Y := X TO 8 DO N[Y] := QMark;
  267.              DoExtension(X+2);
  268.          END;
  269. END; { MakeName }
  270.  
  271. PROCEDURE MakeString(N : NameType; VAR S : FNamType);
  272. VAR
  273.     X : BYTE;
  274.  
  275. BEGIN { MakeString }
  276.     S := '';
  277.     FOR X := 1 TO 8 DO IF N[X] <> Space THEN S := S + N[X];
  278.     S := S + Period;
  279.     FOR X := 9 TO 11 DO IF N[X] <> Space THEN S := S + N[X];
  280. END; { MakeString }
  281.  
  282. FUNCTION Search(S : FNamType; P : INTEGER) : INTEGER;
  283. VAR
  284.    Matched : BOOLEAN;
  285.    Temp    : NameType;
  286.  
  287. BEGIN { Search }
  288.     MakeName(S,Temp);
  289.     Matched := FALSE;
  290.     WHILE (P < DirInfo.MaxEnts) AND NOT Matched DO BEGIN
  291.         IF (Compare(Temp,DIR^[P].FName,11) = SAME) AND (DIR^[P].Status = Active)
  292.         THEN Matched := TRUE
  293.         ELSE P := P + 1;
  294.     END;
  295.     IF Matched THEN Search := P ELSE Search := 0;
  296. END; { Search }
  297.  
  298. PROCEDURE CopyFile(VAR F1,F2 : AnyFile; SecsToCopy : INTEGER);
  299. VAR
  300.     RecsToRead  : INTEGER;
  301.     P           : ^BYTE;
  302.     Free,
  303.     BufSize,
  304.     Buffer      : INTEGER;
  305.  
  306. BEGIN { CopyFile }
  307.     Free    := (MemAvail * 16) - 1024;    { just in case }
  308.     BufSize := Free DIV 128;
  309.     Buffer  := BufSize * 128;
  310.     GetMem(P,Buffer);
  311.     WHILE (SecsToCopy > 0) DO BEGIN
  312.         IF BufSize <= SecsToCopy THEN RecsToRead := BufSize
  313.         ELSE RecsToRead := SecsToCopy;
  314.         BLOCKREAD(F1,P^,RecsToRead);
  315.         BLOCKWRITE(F2,P^,RecsToRead);
  316.         SecsToCopy := SecsToCopy - RecsToRead;
  317.     END;
  318.     FREEMEM(P,Buffer);
  319. END; { CopyFile }
  320.  
  321. FUNCTION UserAbort : BOOLEAN;
  322. VAR
  323.     Ch : CHAR;
  324.  
  325. BEGIN { UserAbort }
  326.     UserAbort := FALSE;
  327.     IF KEYPRESSED THEN BEGIN
  328.         READ(KBD,Ch);
  329.         IF Ch = CHR(3) THEN BEGIN
  330.             WRITELN; WRITELN('User Abort'); WRITELN;
  331.             UserAbort := TRUE
  332.         END;
  333.     END;
  334. END; { UserAbort }
  335.  
  336. PROCEDURE Extract;
  337. VAR
  338.     Drive   : STRING[3];
  339.     OutName : FNamType;
  340.     P       : INTEGER;
  341.     S       : FNamType;
  342.     X       : INTEGER;
  343.  
  344. PROCEDURE ExtractOne(OutName : FNamType; P : INTEGER);
  345. VAR
  346.     OutFile : AnyFile;
  347.  
  348. BEGIN { ExtractOne }
  349.     ASSIGN(OutFile,OutName);
  350.     REWRITE(OutFile);
  351.     SEEK(LibFile,DIR^[P].Start);
  352.     CopyFile(LibFile,OutFile,DIR^[P].Count);
  353.     CLOSE(OutFile);
  354.     WRITELN(OutName,' extracted');
  355. END; { ExtractOne }
  356.  
  357. BEGIN { Extract }
  358.     GetFileName('File(s) to extract',OutName);
  359.     IF OutName <> '' THEN BEGIN
  360.         X := POS(Colon,OutName);
  361.         IF X <> 0 THEN BEGIN
  362.             Drive := COPY(OutName,1,X);
  363.             DELETE(OutName,1,X);
  364.         END
  365.         ELSE Drive := '';
  366.         P := Search(OutName,1);
  367.         IF P = 0 THEN WRITELN(OutName,NoFileMsg)
  368.         ELSE WHILE (P <> 0) AND (NOT UserAbort) DO BEGIN
  369.                 MakeString(DIR^[P].FName,S);
  370.                 ExtractOne(Drive + S,P);
  371.                 P := Search(OutName,P+1);
  372.              END;
  373.     END;
  374. END; { Extract }
  375.  
  376. PROCEDURE DeleteFile;
  377. VAR
  378.     OutName : FNamType;
  379.     P       : INTEGER;
  380.  
  381. PROCEDURE DeleteOne( P : INTEGER );
  382. BEGIN { DeleteOne }
  383.     DIR^[P].Status   := Deleted;
  384.     LibChanged       := TRUE;
  385.     DirInfo.LiveEnts := DirInfo.LiveEnts - 1;
  386.     PrintFileName(DIR^[P]);
  387.     WRITELN(' deleted');
  388. END; { DeleteOne }
  389.  
  390. BEGIN { DeleteFile }
  391.     GetFileName('File(s) to delete',OutName);
  392.     IF OutName <> '' THEN BEGIN
  393.         P := Search(OutName,1);
  394.         IF P = 0 THEN WRITELN(OutName,NoFileMsg)
  395.         ELSE WHILE (P <> 0) AND (NOT UserAbort) DO BEGIN
  396.                 DeleteOne(P);
  397.                 P := Search(OutName,P+1);
  398.              END;
  399.     END;
  400. END; { DeleteFile }
  401.  
  402. PROCEDURE AddFiles;
  403. CONST
  404.     SrchFirst = 17;
  405.     SrchNext  = 18;
  406.     SetDMA    = 26;
  407.     DmaBase   = 51;
  408.     FCBRC     = 15;
  409.     FCBEX     = 12;
  410.  
  411. TYPE
  412.     BufferType   = ARRAY[0..127] OF BYTE;
  413.     FcbType      = ARRAY[0..32] OF BYTE;
  414.     FileRecPtr   = ^FileRec;
  415.     FileRec      = RECORD
  416.                       Next : FileRecPtr;
  417.                       Name : NameType;
  418.                    END;
  419.  
  420. VAR
  421.     Buffer   : BufferType;
  422.     Drive    : STRING[3];
  423.     Fcb      : FcbType;
  424.     ListHead : FileRecPtr;
  425.     ListTail : FileRecPtr;
  426.     Name     : NameType;
  427.     P,Q      : FileRecPtr;
  428.     S        : FNamType;
  429.     X        : BYTE;
  430.     Which    : BYTE;
  431.  
  432.  
  433. PROCEDURE AddOne( FN : NameType);
  434. LABEL 99;
  435. VAR
  436.     Found    : BOOLEAN;
  437.     P        : INTEGER;
  438.     S        : FNamType;
  439.     TempFile : AnyFile;
  440.  
  441. BEGIN { AddOne }
  442.     P     := 1;
  443.     Found := FALSE;
  444.     WHILE (P < DirInfo.MaxEnts) AND NOT Found DO
  445.         IF (DIR^[P].Status = Deleted) OR (DIR^[P].Status = UnUsed) THEN Found := TRUE
  446.         ELSE P := P + 1;
  447.     IF NOT Found THEN BEGIN
  448.         WRITELN('Library is FULL');
  449.         GOTO 99;
  450.     END;
  451.     MakeString(FN,S);
  452.     ASSIGN(TempFile,Drive+S);
  453.     {$I-}
  454.     RESET(TempFile);
  455.     {$I+}
  456.     IF IORESULT <> 0 THEN BEGIN
  457.         WRITELN(S,NoFileMsg);
  458.         GOTO 99;
  459.     END;
  460.     WITH DIR^[P] DO BEGIN
  461.         Status := 0;
  462.         FName  := FN;
  463.         Start  := FILESIZE(LibFile);
  464.         Count  := FILESIZE(TempFile);
  465.         CRC    := ZeroCRC;
  466.     END;
  467.     SEEK(LibFile,FILESIZE(LibFile));
  468.     CopyFile(TempFile,LibFile,FILESIZE(TempFile));
  469.     CLOSE(TempFile);
  470.     LibChanged := TRUE;
  471.     WITH DirInfo DO BEGIN
  472.         LiveEnts  := LiveEnts + 1;
  473.     END;
  474.     WRITELN(Drive+S,' added');
  475. 99:
  476. END; { AddOne }
  477.  
  478. PROCEDURE InitList;
  479. BEGIN
  480.     ListTail := NIL;
  481.     ListHead := NIL;
  482. END;
  483.  
  484. PROCEDURE InitFcb(Name : NameType);
  485. VAR
  486.     X : BYTE;
  487.  
  488. BEGIN
  489.     IF Drive = '' THEN Fcb[0] := 0
  490.     ELSE Fcb[0] := ORD(Drive[1]) - ORD('@');
  491.     Fcb[FCBEX] := 0;
  492.     Fcb[FCBRC] := 0;
  493.     Fcb[32]    := 0;
  494.     Move(Name,Fcb[1],11);
  495. END;
  496.  
  497. PROCEDURE AddName(Entry : NameType);
  498. VAR
  499.     P : FileRecPtr;
  500.  
  501. BEGIN { AddName }
  502.     NEW(P);
  503.     P^.Name := Entry;
  504.     P^.Next := NIL;
  505.     IF ListHead = NIL THEN ListHead := P
  506.     ELSE ListTail^.Next := P;
  507.     ListTail := P;
  508. END; { AddName }
  509.  
  510. PROCEDURE DoDMA86;
  511. VAR
  512.     Regs : BdosRegs;
  513.  
  514. BEGIN { DoDMA86 }
  515.     WITH Regs DO BEGIN
  516.         CX := SetDMA;
  517.         DX := OFS(Buffer);
  518.         DS := SEG(Buffer);
  519.     END;
  520.     BDOS(Regs);
  521.     WITH Regs DO BEGIN
  522.         CX := DMABase;
  523.         DX := SEG(Buffer);
  524.         DS := SEG(Buffer);
  525.     END;
  526.     BDOS(Regs);
  527. END; { DoDMA86 }
  528.  
  529. FUNCTION Bdos86(FunctNum : BYTE) : BYTE;
  530. VAR
  531.     Regs : BdosRegs;
  532.  
  533. BEGIN { Bdos86 }
  534.     WITH Regs DO BEGIN
  535.         CX := FunctNum;
  536.         DX := OFS(Fcb);
  537.         DS := SEG(Fcb);
  538.     END;
  539.     BDOS(Regs);
  540.     Bdos86 := Regs.AX AND $FF;
  541. END; { Bdos86 }
  542.  
  543. FUNCTION SysDir(Funct : BYTE; VAR Entry : NameType) : BOOLEAN;
  544. VAR
  545.     BufIndex,X : BYTE;
  546.  
  547. BEGIN { SysDir }
  548.     BufIndex  := Bdos86(Funct);
  549.     IF BufIndex <> 255 THEN BEGIN
  550.         BufIndex := BufIndex SHL 5;
  551.         MOVE(Buffer[BufIndex+1],Entry,11);
  552.         FOR X := 1 TO 11 DO Entry[X] := CHR(ORD(Entry[X]) AND $7F);
  553.         SysDir := TRUE;
  554.     END
  555.     ELSE SysDir := FALSE;
  556. END; { SysDir }
  557.  
  558. BEGIN { AddFiles }
  559.     GetFileName('File(s) to Add',S);
  560.     IF S <> '' THEN BEGIN
  561.         DoDMA86;
  562.         InitList;
  563.         X := POS(Colon,S);
  564.         IF X <> 0 THEN BEGIN
  565.             Drive := COPY(S,1,X);
  566.             DELETE(S,1,X);
  567.         END
  568.         ELSE Drive := '';
  569.         MakeName(S,Name);
  570.         InitFcb(Name);
  571.         Which  := SrchFirst;
  572.         WHILE SysDir(Which,Name) DO BEGIN
  573.               AddName(Name);
  574.               Which := SrchNext;
  575.         END;
  576.         P := ListHead;
  577.         WHILE P <> NIL DO BEGIN
  578.             AddOne(P^.Name);
  579.             Q := P;
  580.             P := P^.Next;
  581.             DISPOSE(Q);
  582.         END;
  583.     END;
  584. END; { AddFiles }
  585.  
  586. PROCEDURE WriteDir(VAR F : AnyFile; VAR D : DirPtr; NumSectors : INTEGER);
  587. BEGIN { WriteDir }
  588.     SEEK(F,0);
  589.     BLOCKWRITE(F,D^,NumSectors);
  590. END; { WriteDir }
  591.  
  592. PROCEDURE CloseLibrary;
  593. BEGIN { CloseLibrary }
  594.     IF LibChanged
  595.     THEN WriteDir(LibFile,DIR,DirInfo.MaxEnts DIV SlotsPerSect);
  596.     CLOSE(LibFile);
  597.     RELEASE(Heap);
  598.     Initialize;
  599. END; { CloseLibrary }
  600.  
  601. PROCEDURE InitDir(VAR D : DirPtr; NumSlots,NumSects : INTEGER);
  602. VAR
  603.     I : INTEGER;
  604.  
  605. BEGIN { InitDir }
  606.     FOR I := 1 TO NumSlots-1 DO BEGIN
  607.         D^[I].Status := UnUsed;
  608.         FILLCHAR(D^[I].FName,11,Space);
  609.     END;
  610.     WITH D^[0] DO BEGIN
  611.         Status := Active;
  612.         Start  := $00;
  613.         Count  := NumSects;
  614.         FILLCHAR(FName,11,Space);
  615.         FILLCHAR(CRC,16,UnUsed);    { To assure compatibility with CRC }
  616.     END;
  617. END; { InitDir }
  618.  
  619. FUNCTION CreateLibrary(VAR LF : AnyFile; VAR D : DirPtr) : BOOLEAN;
  620. LABEL 99;
  621.  
  622. VAR
  623.     NumSects : INTEGER;
  624.     NumSlots : INTEGER;
  625.  
  626. BEGIN { CreateLibrary }
  627.     CreateLibrary := FALSE;
  628.     IF NOT GetDirSize(NumSlots,NumSects,1) THEN GOTO 99;
  629.     GETMEM(D,NumSects * SectorSize);
  630.     REWRITE(LF);
  631.     InitDir(D,NumSlots,NumSects);
  632.     WriteDir(LF,D,NumSects);
  633.     FREEMEM(D,NumSects * SectorSize);
  634.     CLOSE(LF);
  635.     RESET(LF);
  636.     CreateLibrary := TRUE;
  637. 99:
  638. END; { CreateLibrary }
  639.  
  640. PROCEDURE OpenLibrary(VAR LF : AnyFile; VAR D : DirPtr; VAR FN : FNamType);
  641. LABEL 99;
  642. BEGIN { OpenLibrary }
  643.     ASSIGN(LF,FN);
  644.     {$I-}
  645.     RESET(LF);
  646.     {$I+}
  647.     IF (IORESULT <> 0) THEN IF NOT CreateLibrary(LF,D) THEN GOTO 99;
  648.     MARK(Heap);
  649.     ReadDir;
  650.     LibOpen := TRUE;
  651.     WRITELN;
  652. 99:
  653. END; { OpenLibrary }
  654.  
  655. PROCEDURE Open(VAR LF : AnyFile; VAR D : DirPtr; VAR FN : FNamType);
  656. VAR
  657.     S : FNamType;
  658.  
  659. BEGIN { Open }
  660.     GetFileName('Library file',S);
  661.     IF S <> '' THEN BEGIN
  662.         IF LibOpen THEN CloseLibrary;
  663.         FN := S;
  664.         WHILE FN[1] = Space DO DELETE(FN,1,1);
  665.         IF POS(Period,FN) = 0 THEN FN := FN + LibExt;
  666.         OpenLibrary(LF,D,FN);
  667.     END;
  668. END; { Open }
  669.  
  670. PROCEDURE Reorganize;
  671. LABEL 99;
  672.  
  673. VAR
  674.    NewDir   : DirPtr;
  675.    P,N      : INTEGER;
  676.    NewLib   : AnyFile;
  677.    NumSects : INTEGER;
  678.    NumSlots : INTEGER;
  679.    S        : FNamType;
  680.  
  681. PROCEDURE ShellSort;
  682. LABEL 0;
  683. VAR
  684.     I,H,J : INTEGER;
  685.     Temp  : DirEntryType;
  686.  
  687. BEGIN { ShellSort }
  688.     H := 1;
  689.     REPEAT H := 3*H + 1; UNTIL H > DirInfo.HiSlotNum;
  690.     REPEAT
  691.         H := H DIV 3;
  692.         FOR I := H + 1 TO DirInfo.HiSlotNum DO BEGIN
  693.             MOVE(DIR^[I],Temp,SIZEOF(Temp));
  694.             J := I;
  695.             WHILE Compare(DIR^[J-H],Temp.Status,12) = GT DO BEGIN
  696.                 MOVE(DIR^[J-H],DIR^[J],SIZEOF(DirEntryType));
  697.                 J := J - H;
  698.                 IF J <= H THEN GOTO 0;
  699.             END; { While }
  700.         0: MOVE(Temp,DIR^[J],SIZEOF(Temp));
  701.         END; { For }
  702.     UNTIL H = 1;
  703. END; { ShellSort }
  704.  
  705. BEGIN { Reorganize }
  706.     GetFileName('Name of New Library',S);
  707.     IF S = '' THEN GOTO 99;
  708.     IF POS(Period,S) = 0 THEN S := S + LibExt;
  709.     IF NOT GetDirSize(NumSlots,NumSects,DirInfo.LiveEnts) THEN GOTO 99;
  710.     GETMEM(NewDir,NumSects * SectorSize);
  711.     ASSIGN(NewLib,S);
  712.     REWRITE(NewLIb);
  713.     InitDir(NewDir,NumSlots,NumSects);
  714.     WriteDir(NewLib,NewDir,NumSects);
  715.     ShellSort;
  716.     P := 1;
  717.     N := 1;
  718.     WHILE (P < DirInfo.MaxEnts) AND (DIR^[P].Status <> UnUsed) DO BEGIN
  719.         IF UserAbort THEN GOTO 99;
  720.         IF DIR^[P].Status = Active THEN BEGIN
  721.             NewDir^[N] := DIR^[P];
  722.             SEEK(NewLib,FILESIZE(NewLib));
  723.             NewDir^[N].Start  := FILEPOS(NewLib);
  724.             NewDir^[N].CRC    := ZeroCRC;
  725.             SEEK(LibFile,DIR^[P].Start);
  726.             CopyFile(LibFile,NewLib,DIR^[P].Count);
  727.             PrintFileName(DIR^[P]);
  728.             WRITELN(' copied to new library');
  729.             N := N + 1;
  730.         END;
  731.         P := P + 1;
  732.     END;
  733.     WriteDir(NewLib,NewDir,NumSects);
  734.     FREEMEM(NewDir,NumSects * SectorSize);
  735.     CLOSE(NewLib);
  736.     CloseLibrary;
  737.     LibName := S;
  738.     OpenLibrary(LibFile,DIR,LibName);
  739. 99:
  740. END; { Reorganize }
  741.  
  742. BEGIN { UnLu }
  743.     Initialize;
  744.     WRITELN(Version,CopyRight); WRITELN;
  745.     REPEAT
  746.         IF LibOpen THEN WRITELN(LibName,':');
  747.         WRITE('L(ist, E(xtract, O(pen, C(lose, A(dd, D(elete, R(eorg, Q(uit ? ');
  748.         REPEAT
  749.             READ(KBD,Ch);
  750.             Ch := UPCASE(Ch);
  751.         UNTIL Ch IN ['L','E','O','C','Q','A','D','R',#3];
  752.         WRITELN(Ch);
  753.         CASE Ch OF
  754.             #3  : HALT;
  755.             'L' : IF LibOpen THEN ListNames ELSE WRITELN(NoLibMsg);
  756.             'E' : IF LibOpen THEN Extract ELSE WRITELN(NoLibMsg);
  757.             'A' : IF NOT LibOpen THEN WRITELN(NoLibMsg)
  758.                   ELSE IF NOT LibRO THEN AddFiles ELSE WRITELN(ROMsg);
  759.             'D' : IF NOT LibOpen THEN WRITELN(NoLibMsg)
  760.                   ELSE IF NOT LibRO THEN DeleteFile ELSE WRITELN(ROMsg);
  761.             'O' : Open(LibFile,DIR,LibName);
  762.             'C' : IF LibOpen THEN CloseLibrary ELSE WRITELN(NoLibMsg);
  763.             'R' : IF LibOpen THEN Reorganize ELSE WRITELN(NoLibMsg);
  764.             'Q' : IF LibOpen THEN CloseLibrary;
  765.         END; { Case }
  766.     UNTIL Ch = 'Q';
  767. END. { UnLu }
  768.