home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / LU10A.ZIP / LU10A.PAS
Encoding:
Pascal/Delphi Source File  |  1989-03-20  |  19.3 KB  |  562 lines

  1. program LibraryUtility;   { written 10/09/84 by Steve Freeman
  2.  
  3.   This program was written to function as Gary Novosielski's LU.  As such it
  4.   will function as a utility to manipulate library members under any operating
  5.   system which will support TURBO Pascal.  Minor rewrites may be necessary for
  6.   other versions of Pascal.
  7.  
  8.   This program is placed into the Public Domain by the author and, as a Public
  9.   Domain program, may NOT be used for commercial purposes.
  10. }
  11.  
  12. const ProgramVersion = '1.00';
  13.       BufferSize = 127;      { maximum size of data buffer - 1 }
  14.       EntriesPerBuffer = 4;  { (BufferSize+1)/32 }
  15.       maxent = 128;          { maximum dir entries this program will take }
  16.  
  17. type TimeType = integer;
  18.      FileNameType = array[1..11] of char;
  19.      LibFileType = file;
  20.  
  21.      EntryType = record
  22.                    status: byte;
  23.                    name: array[1..8] of char;
  24.                    ext:  array[1..3] of char;
  25.                    index: integer;
  26.                    length: integer;
  27.                    CRC: integer;
  28.                    CreationDate: integer;
  29.                    LastChangeDate: integer;
  30.                    CreationTime: TimeType;
  31.                    LastChangeTime: TimeType;
  32.                    PadCount: byte;
  33.                    filler: array[27..31] of byte;
  34.                  end;
  35.      EntryPtr = ^EntryType;
  36.  
  37.      hexstr = string[4];
  38.      maxstr = string[255];
  39.      filename = string[12];
  40.  
  41. var buffer: array[0..BufferSize] of byte;
  42.     library, file2: file;
  43.     SizeFile: file of byte;
  44.     DirectoryChanged: boolean;
  45.     LibName, fname: filename;
  46.     LibSize, NumEntries: integer;
  47.     LibEntry: EntryType;
  48.     Dir: array[0..maxent] of EntryPtr;
  49.     active, unused, deleted: integer;
  50. {.cp7}
  51.   procedure WaitKey;
  52.     var c: char;
  53.     begin
  54.       write(^M^J,'Press any key to continue...');
  55.       repeat until keypressed;
  56.       read(kbd,c);
  57.     end;
  58. {.cp13}
  59.   function Confirm: boolean;
  60.     var c: char;
  61.     begin
  62.       write('Confirm operation (Y/N): ');
  63.       repeat
  64.           read(kbd,c);
  65.           c := upcase(c);
  66.         until (c in ['Y','N']);
  67.       writeln(c);
  68.       if c = 'Y'
  69.         then Confirm := true
  70.         else Confirm := false
  71.     end;
  72. {.cp9}
  73.   function CommandLine: maxstr;
  74.     var len, i: integer;
  75.         str: maxstr;
  76.     begin
  77.       str := '';
  78.       len := mem[cseg:$80];
  79.       if len>1
  80.         then for i:=2 to len do str := str + chr(mem[cseg:$80+i]);
  81.       CommandLine := str;
  82.     end;
  83. {.cp13}
  84.   function hex(num: integer): hexstr;
  85.     var i, j: integer;
  86.         h: string[16];
  87.         str: hexstr;
  88.     begin
  89.       str := '0000';   h := '0123456789ABCDEF';   j := num;
  90.       for i:=4 downto 1
  91.         do begin
  92.              str[i] := h[(j and 15)+1];
  93.              j := j shr 4;
  94.            end;
  95.       hex := str;
  96.     end;
  97. {.cp14}
  98.   procedure MakeName(f: filename; var name: FileNameType);
  99.     var dotpos, endname, i: integer;
  100.     begin
  101.       for i:=1 to 11 do name[i] := ' ';
  102.       dotpos := pos('.',f);
  103.       if dotpos > 0
  104.         then endname := dotpos-1
  105.         else endname := length(f);
  106.       for i:=1 to length(f) do f[i] := upcase(f[i]);
  107.       if dotpos > 0
  108.         then for i:=1 to 3 do if f[dotpos+i]<>' '
  109.                                 then name[8+i] := f[dotpos+i];
  110.       for i:=1 to endname do name[i] := f[i];
  111.     end;
  112. {.cp8}
  113.   procedure PutName(f: filename; n: integer);
  114.     var i: integer;
  115.         name: FileNameType;
  116.     begin
  117.       MakeName(f,name);
  118.       for i:=1 to 8 do Dir[n]^.name[i] := name[i];
  119.       for i:=1 to 3 do Dir[n]^.ext[i]  := name[i+8];
  120.     end;
  121. {.cp29}
  122.   function FindMember(f: filename): integer;
  123.     var member, dotpos, endname, i, k: integer;
  124.         lookup: FileNameType;
  125.         found: boolean;
  126.  
  127.     function NamesMatch(entry: integer): boolean;
  128.       var match: boolean;
  129.       begin
  130.         NamesMatch := true;
  131.         with Dir[entry]^
  132.           do begin
  133.                if (status <> 0) and (status <> $FE) then NamesMatch := false;
  134.                for k:=1 to 8 do if name[k]<>lookup[k] then NamesMatch := false;
  135.                for k:=1 to 3 do if ext[k]<>lookup[8+k] then NamesMatch := false;
  136.              end;
  137.       end;
  138.  
  139.     begin
  140.       MakeName(f,lookup);
  141.       found := false;   i := 1;
  142.       while not(found) and (i<NumEntries)
  143.         do if NamesMatch(i)
  144.              then found := true
  145.              else i := i + 1;
  146.  
  147.       if (active=1) or not(found)
  148.         then FindMember := 0
  149.         else FindMember := i
  150.     end;
  151. {.cp9}
  152.   function Parse(f: filename): filename;
  153.     var i: integer;
  154.     begin
  155.       for i:=1 to length(f) do f[i]:=upcase(f[i]);
  156.       i := pos('.',f);
  157.       if i>0 then f:=copy(f,1,i-1);
  158.       f := f + '.LBR';
  159.       Parse := f;
  160.     end;
  161. {.cp13}
  162.   procedure WriteDirectoryToDisk(var lib: LibFileType);
  163.     var member, i: integer;
  164.     begin
  165.       reset(lib);
  166.       member := 0;
  167.       while member < NumEntries
  168.         do begin
  169.              for i:=0 to EntriesPerBuffer-1 do move(Dir[member+i]^,buffer[32*i],32);
  170.              blockwrite(lib,buffer,1);
  171.              member := member + 4
  172.            end;
  173.       DirectoryChanged := false
  174.     end;
  175. {.cp6}
  176.   procedure ZeroEntry(n: integer);
  177.     begin
  178.       fillchar(Dir[n]^,32,chr(0));      {clear the record}
  179.       fillchar(Dir[n]^.name[1],11,' '); {clear file name}
  180.       Dir[n]^.status := -1;             {mark unused}
  181.     end;
  182. {.cp38}
  183.   procedure SortDir;
  184.     var i, j: integer;
  185.  
  186.     function larger(a, b: integer): boolean;
  187.       var ok, x: integer;
  188.           c1, c2: char;
  189.       begin
  190.         ok := 0;   x := 1;
  191.         if (Dir[a]^.status <> 0) and (Dir[b]^.status <> 0) then ok := 2;
  192.         if (Dir[a]^.status <> 0) and (ok = 0) then ok := 1;
  193.         if (Dir[b]^.status <> 0) and (ok = 0) then ok := 2;
  194.         while (x < 12) and (ok=0)
  195.           do begin
  196.                c1 := Dir[a]^.name[x];   c2 := Dir[b]^.name[x];
  197.                if c1 > c2 then ok := 1;
  198.                if c1 < c2 then ok := 2;
  199.                x := x + 1
  200.              end;
  201.         if ok=1
  202.           then larger := true
  203.           else larger := false
  204.       end;
  205.  
  206.     procedure swap(x, y: integer);
  207.       var temp: EntryPtr;
  208.       begin
  209.         temp   := Dir[x];
  210.         Dir[x] := Dir[y];
  211.         Dir[y] := temp
  212.       end;
  213.  
  214.     begin
  215.       for i:=1 to NumEntries-1
  216.         do if Dir[i]^.status <> 0 then ZeroEntry(i);
  217.       for i:=1 to NumEntries-2
  218.         do begin
  219.              for j:=i+1 to NumEntries-1
  220.                do if larger(i,j) then swap(i,j);
  221.            end;
  222.     end;
  223. {.cp22}
  224.   procedure CreateDirectory;
  225.     var i: integer;
  226.     begin
  227.       rewrite(library);
  228.       clrscr;  writeln('Creating a new library.  Name = ',LibName);
  229.       write('How many entries? ');  readln(i);
  230.       NumEntries := i + 1; {add 1 for Directory entry}
  231.       i := NumEntries MOD 4;
  232.       if i<>0 then NumEntries := NumEntries + (4 - i);
  233.  
  234.       for i:=0 to NumEntries-1
  235.         do begin
  236.              new(Dir[i]);
  237.              ZeroEntry(i);
  238.            end;
  239.  
  240.       Dir[0]^.status := 0; {directory entry is always used}
  241.       Dir[0]^.length := NumEntries DIV 4;
  242.       active := 1;   unused := NumEntries - 1;   deleted := 0;
  243.       WriteDirectoryToDisk(library);
  244.     end;
  245. {.cp26}
  246.   procedure GetDirectory;
  247.     var i, offset: integer;
  248.     begin
  249.       offset := 0;   DirectoryChanged := false;
  250.       LibSize := (1 + filesize(library)) DIV 8;  {in kilobytes}
  251.       blockread(library,buffer,1);
  252.       new(Dir[0]);                 {make space for directory header}
  253.       move(buffer[0],Dir[0]^,32);  {move header entry}
  254.       NumEntries := (128 * Dir[0]^.length) DIV 32;
  255.       for i:=1 to NumEntries-1
  256.         do begin
  257.              if (i MOD EntriesPerBuffer) = 0
  258.                then begin {read next block}
  259.                       blockread(library,buffer,1);
  260.                       offset := offset + EntriesPerBuffer;
  261.                     end;
  262.              new(Dir[i]);
  263.              move(buffer[32*(i-offset)],Dir[i]^,32);
  264.            end;
  265.       active := 1;   unused := 0;   deleted := 0;
  266.       for i:=1 to NumEntries-1
  267.         do if Dir[i]^.status=0
  268.              then active := active + 1
  269.              else if Dir[i]^.status=$FE
  270.                     then deleted := deleted + 1
  271.                     else unused := unused + 1;
  272.     end;
  273. {.cp8}
  274.   procedure OpenLibrary;
  275.     begin
  276.       assign(library,LibName);
  277.       {$I-} reset(library) {$I+};
  278.       if IOresult=0
  279.         then GetDirectory
  280.         else CreateDirectory;
  281.     end;
  282. {.cp23}
  283.   procedure Directory;
  284.     var i, j: integer;
  285.     begin
  286.       clrscr;
  287.       writeln('Library ',LibName,' is ',LibSize,'K',^M^J);
  288.       writeln('  name          index  length    CRC');
  289.       writeln('------------------------------------');
  290.       for i:=1 to NumEntries-1
  291.         do with Dir[i]^
  292.              do begin
  293.                   if status<>$FF
  294.                     then begin
  295.                            for j:=1 to 8 do write(name[j]);
  296.                            write('.');
  297.                            for j:=1 to 3 do write(ext[j]);
  298.                            write(' ',index:8,length:8,'   ',hex(CRC));
  299.                            if status=$FE then write('   deleted');
  300.                            writeln;
  301.                          end;
  302.                 end;
  303.       writeln(^M^J,active,' active, ',unused,' unused, ',deleted,' deleted: ',active+unused+deleted,' total entries.');
  304.       WaitKey;
  305.     end;
  306. {.pa}
  307.   procedure Extract;
  308.     var fname2: filename;
  309.         i, blocknum, bytenum: integer;
  310.     begin
  311.       clrscr;   write('Enter filename to extract: ');  readln(fname2);
  312.       if length(fname2)>0
  313.         then begin
  314.                i := FindMember(fname2);
  315.                if i>0
  316.                  then begin
  317.                         assign(file2,fname2);
  318.                         rewrite(file2);
  319.                         with Dir[i]^
  320.                           do begin
  321.                                seek(library,index);
  322.                                blocknum := 1;   bytenum := 0;
  323.                                while blocknum <= length
  324.                                  do begin
  325.                                       blockread(library,buffer,1);
  326.                                       if blocknum<=length
  327.                                         then blockwrite(file2,buffer,1)
  328.                                         else begin
  329.                                                close(file2); {save disk info}
  330.                                                assign(SizeFile,fname2);
  331.                                                reset(SizeFile);
  332.                                                seek(SizeFile,filesize(SizeFile));
  333.                                                while bytenum < ((128 - PadCount) MOD 128)
  334.                                                  do begin
  335.                                                       write(SizeFile,buffer[bytenum]);
  336.                                                       bytenum := bytenum + 1
  337.                                                     end;
  338.                                                close(SizeFile);
  339.                                                reset(file2); {for later close}
  340.                                              end;
  341.                                       blocknum := blocknum + 1
  342.                                     end;
  343.                              end;
  344.                         close(file2);
  345.                       end
  346.                  else writeln('member was not found!!');
  347.              end;
  348.       WaitKey;
  349.     end;
  350. {.cp27}
  351.   procedure Delete;
  352.     var fname2: filename;
  353.         i: integer;
  354.         ok: boolean;
  355.     begin
  356.       clrscr;   write('Enter member to delete: ');  readln(fname2);
  357.       if length(fname2)>0
  358.          then begin
  359.                 i := FindMember(fname2);
  360.                 if i>0
  361.                   then begin
  362.                          ok := Confirm;
  363.                          write('Member ',fname2);
  364.                          if ok
  365.                            then begin
  366.                                   Dir[i]^.status := $FE;
  367.                                   deleted := deleted + 1;
  368.                                   active := active - 1;
  369.                                   writeln(' was deleted.');
  370.                                   DirectoryChanged := true;
  371.                                 end
  372.                            else writeln(' was NOT deleted.')
  373.                        end
  374.                   else writeln(fname2,' does not exist.');
  375.                 WaitKey;
  376.               end;
  377.     end;
  378. {.cp21}
  379.   procedure Undelete;
  380.     var fname2: filename;
  381.         i: integer;
  382.         ok: boolean;
  383.     begin
  384.       clrscr;   write('Enter member to undelete: ');  readln(fname2);
  385.       if length(fname2)>0
  386.          then begin
  387.                 i := FindMember(fname2);
  388.                 if i>0
  389.                   then begin
  390.                          Dir[i]^.status := 0;
  391.                          deleted := deleted - 1;
  392.                          active := active + 1;
  393.                          writeln(fname2,' was undeleted.');
  394.                          DirectoryChanged := true;
  395.                        end
  396.                   else writeln(fname2,' does not exist.');
  397.                 WaitKey;
  398.               end;
  399.     end;
  400. {.pa}
  401.   procedure Add;
  402.     var fname2: filename;
  403.         EntryLength, EntryIndex, SizeOfFile, number, i: integer;
  404.     begin
  405.       number := 0;   i := 1;
  406.       while (number = 0) and (i < NumEntries)
  407.         do begin
  408.              if (Dir[i]^.status=$FF) and (number=0)
  409.                then number := i
  410.                else i := i + 1;
  411.            end;
  412.       clrscr;
  413.       if number > 0
  414.         then begin
  415.                write('Enter member to add: ');  readln(fname2);
  416.                if length(fname2)>0
  417.                  then begin
  418.                         if FindMember(fname2) = 0
  419.                           then begin
  420.                                  assign(SizeFile,fname2);
  421.                                  {$I-} reset(SizeFile) {$I+};
  422.                                  if IOresult=0
  423.                                    then begin
  424.                                           SizeOfFile := filesize(SizeFile);
  425.                                           close(SizeFile);
  426.  
  427.                                           assign(file2,fname2);
  428.                                           reset(file2);
  429.                                           EntryIndex  := filesize(library);
  430.                                           EntryLength := filesize(file2);
  431.                                           seek(library,EntryIndex);
  432.                                           while not(eof(file2))
  433.                                             do begin
  434.                                                  blockread(file2,buffer,1);
  435.                                                  blockwrite(library,buffer,1)
  436.                                                end;
  437.                                           close(file2);
  438.  
  439.                                           fillchar(Dir[number]^,32,chr(0)); {status:=0}
  440.                                           Dir[number]^.index  := EntryIndex;
  441.                                           Dir[number]^.length := EntryLength;
  442.                                           Dir[number]^.PadCount := (128 - (SizeOfFile MOD 128)) and $7F;
  443.                                           PutName(fname2,number);
  444.                                           unused := unused - 1;
  445.                                           active := active + 1;
  446.                                           write('Member ',fname2,' was added.');
  447.                                           DirectoryChanged := true;
  448.                                         end
  449.                                    else writeln('File ',fname2,' was not found.');
  450.                                end
  451.                           else writeln(fname2,' is already a member.');
  452.                       end;
  453.              end
  454.         else writeln('There are no available places to put this entry.');
  455.       WaitKey;
  456.     end;
  457. {.pa}
  458.   procedure Reorganize;
  459.     var i, j: integer;
  460.     begin
  461.       SortDir;
  462.       assign(file2,'WORK-$$$.LBR');
  463.       reset(library);   rewrite(file2);
  464.       WriteDirectoryToDisk(file2);
  465.       for i:=1 to NumEntries-1
  466.         do with Dir[i]^
  467.              do begin
  468.                   if (status = 0) and (length > 0)
  469.                     then begin
  470.                            writeln('Copying: ',name,'.',ext,'  ',filepos(file2));
  471.                            seek(library,index);
  472.                            index := filepos(file2);
  473.                            for j:=1 to length
  474.                              do begin
  475.                                   blockread (library,buffer,1);
  476.                                   blockwrite(file2,  buffer,1)
  477.                                 end
  478.                          end
  479.                 end;
  480.       WriteDirectoryToDisk(file2);
  481.       close(file2);     close(library);
  482.       erase(library);   rename(file2,LibName);
  483.       reset(library);
  484.     end;
  485. {.cp8}
  486.   procedure HelpCmdLine;
  487.     begin
  488.       clrscr;
  489.       writeln(^M^J,'You must enter a file name:');
  490.       writeln(^M^J,'LU <filename>[.LBR]');
  491.       writeln(^M^J,'NOTE: the .LBR suffix is optional.');
  492.       WaitKey;
  493.     end;
  494. {.cp14}
  495.   procedure Help;
  496.     begin
  497.       clrscr;
  498.       writeln('Library Utility Commands:',^M^J);
  499.       writeln('Add       - add a new member, can''t be duplicate');
  500.       writeln('Directory - gives the listing of this library''s directory');
  501.       writeln('Extract   - copy a member out to its own file');
  502.       writeln('Kill      - delete a member from the library');
  503.       writeln('Undelete  - reverses the effects of a delete');
  504.       writeln('Reorganize- compresses blank space in library');
  505.       writeln('eXit      - terminate this program');
  506.       writeln('Help      - gives this screen');
  507.       WaitKey;
  508.     end;
  509. {.pa}
  510.   procedure Menu;
  511.     var selection: char;
  512.     begin
  513.       OpenLibrary;
  514.       repeat
  515.           clrscr;
  516.           gotoxy(30,2);  write('Library Utility Menu');
  517.           gotoxy(35,3);  write('version ',ProgramVersion);
  518.           gotoxy(40-length(LibName) DIV 2,5);  write(LibName);
  519.           gotoxy(10,07); write('D - directory');
  520.           gotoxy(10,08); write('E - extract member');
  521.           gotoxy(10,09); write('A - add member');
  522.           gotoxy(10,10); write('K - delete member');
  523.           gotoxy(10,11); write('U - undelete member');
  524.           gotoxy(10,12); write('R - reorganize library');
  525.           gotoxy(10,13); write('X - exit');
  526.           gotoxy(10,14); write('? - help');
  527.           gotoxy(20,20); write('choose one: ');
  528.           repeat
  529.               repeat until keypressed;
  530.               read(kbd,selection);
  531.               selection := upcase(selection);
  532.             until (selection in ['A','D','E','K','R','U','X','?']);
  533.           writeln(selection);
  534.           case selection of
  535.             'A': Add;
  536.             'D': Directory;
  537.             'E': Extract;
  538.             '?': Help;
  539.             'K': Delete;
  540.             'R': Reorganize;
  541.             'U': Undelete;
  542.           end;
  543.         until selection='X';
  544.       if DirectoryChanged then WriteDirectoryToDisk(library);
  545.       close(library);
  546.     end;
  547. {.cp8}
  548. begin {Main}
  549.  
  550.   LibName := Parse(CommandLine);
  551.   if length(CommandLine) = 0
  552.     then
  553.         begin
  554.              write('Enter name of library file:  ');
  555.              Read(fname);
  556.              Libname := Parse(fname);
  557.              Menu;
  558.         end
  559.     else Menu;
  560.  
  561. end.
  562.