[Back to FILES SWAG index]  [Back to Main SWAG index]  [Original]

program CAT;

{$I-}

uses
   dos,
   files, { see end for this unit }
   crt;

type
   arraybuf = array[1..65535] of byte;
   buffer = ^arraybuf;
   chksum = file of searchrec;

procedure error(mess:string);
var
   code:integer;
begin
   code:= ioresult;
   writeln('ERROR:  ', mess);
   {writeln('ERROR CODE:  ', code);}
   halt(1);
end;

procedure delete(drive:char; var success:boolean);
   procedure recurse(tree:directory_tree; var success:boolean);
   var
      info:searchrec;
      buffer:text;
      success2:boolean;
      d:string[79];
   begin
      if tree <> nil then begin
      success2:= true;
      d:= tree^.dir;
         begin
            recurse(tree^.lower_dir, success2);
            tree:= tree^.next;
            success:= success and success2;
            recurse(tree, success2);
            success:= success and success2;
         end;
      chdir(d);
      findfirst('*.*', anyfile, info);
      while (doserror = 0) and (success) do
         begin
            if (info.name <> '.') and (info.name <> '..') then
               begin
                  assign(buffer, info.name);
                  case info.attr of
                     $10: rmdir(info.name);
                     $20: erase(buffer);
                  else
                     success:= false;
                  end;
               end;
            findnext(info);
         end;
   end;
   end;
var
   tree:directory_tree;
begin
   tree:= nil;
   chdir(drive+':\');
   fill_dirtree(drive+':\', tree);
   success:= true;
   recurse(tree, success);
end;

function DriveExist(drive:char):boolean;
var
   fileinfo:searchrec;
begin
   findfirst(drive+':\*.*', anyfile, fileinfo);
   if doserror = 3 then
      driveexist:= false
   else
      driveexist:= true;
end;

procedure work(max,done:longint);
begin
   write(100*(done/max):4:1, '% complete.');
   gotoxy(1, wherey);
end;

procedure help;
begin
   writeln('The Concatinator   Version 1.0   Copyright 1996 by Jack Neely');
   writeln('A large file disk storage and retrieval program.');
   writeln;
   writeln('Usage:   CAT s <storage drive> <filename>');
   writeln('         CAT r <storage dirve> <path>');
   writeln;
   writeln('Commands: ''s'' = Store   ''r'' = Retrive');
   writeln('Storage drive must be the disk drive to store or that a large file is');
   writeln('stored apon.  Specify a path where the file will be placed when');
   writeln('retriving a file.  Specify a filemane when storing a large file.');
   writeln;
   writeln('You can use this program to store those large files that are larger');
   writeln('than a single disk onto multiple disks.  Anything on the disk prior');
   writeln('to storage will be erased.  A checksum file will also be stored on the');
   writeln('first disk of each set.');
   writeln;
   writeln('The author can be reached at hneely@ac.net');
   writeln;
   halt(0);
end;

function num(d:char):word;
begin
   num:= ord(upcase(d)) - 64;
end;

function strn(a:integer):string;
var
   s:string;
   i:integer;
begin
   str(a, s);
   if length(s) < 4 then
      for i:= 1 to 4 - length(s) do
         s:= '0' + s;
   strn:= s;
end;

function return(s:string; b:boolean):integer;
var
   str:string;
   i, c:integer;
begin
   str:= '';
   if b then
      for i:= 1 to 4 do
         str:= str + s[i]
   else
      for i:= 5 to 8 do
         str:= str + s[i];
   val(str, i, c);
   return:= i;
end;

procedure store(filename:string; drive:char);
var
   input, output:file;
   fileinfo, test:searchrec;
   filedata:chksum;
   c, full, disk:longint;
   diskdone:boolean;
   fset, disknum:word;
   success:boolean;
   data:buffer;
   buffersize, readcount, writecount:word;
   ch:char;
begin
   findfirst(filename, anyfile, fileinfo);
   if doserror <> 0 then
      error('File not found: ' + filename);
   new(data);
   c:= 0;
   disknum:= 0;
   diskdone:= true;
   if not DriveExist(drive) then error(drive+': does not exist.');
   randomize;
   fset:= random(9999);
   writeln('This is file set number ', fset, '.');
   assign(input, filename);
   reset(input, 1);
   while c < fileinfo.size do
      begin
         if diskdone then
            begin
               if disknum <> 0 then
                  close(output);
               clreol;
               disk:= 0;
               disknum:= disknum + 1;
               write('Insert disk ', disknum, ' and press [ENTER].');
               readln;
               diskdone:= false;
               buffersize:= sizeof(arraybuf);
               full:= disksize(num(drive));
               if disknum = 1 then
                  begin
                     writeln('Approximately ', (1+(fileinfo.size div disksize(num(drive)))), ' of these disks are needed.');
                     write('Continue? (Y/N)');
                     ch:= readkey;
                     if not ((ch = 'y') or (ch = 'Y')) then
                        halt(0);
                     writeln;
                  end;
               if disksize(num(drive)) <> diskfree(num(drive)) then
                  begin
                     findfirst(drive+':\*.cat', anyfile, test);
                     if return(test.name, true) = fset then
                        error('This disk is of this same set.');
                     delete(drive, success);
                     if not success then
                        error('Some existing file(s) on destination disk could not be removed.');
                  end;
                  assign(output, drive+':\'+strn(fset)+strn(disknum)+'.cat');
                  rewrite(output, 1);
               if disknum = 1 then
                  begin
                     assign(filedata, drive+':\check.sum');
                     rewrite(filedata);
                     write(filedata, fileinfo);
                     close(filedata);
                     full:= diskfree(num(drive));
                  end;
            end;
         if full - disk < buffersize then
            begin
               buffersize:= full - disk;
               diskdone:= true;
            end;
         blockread(input, data^, buffersize, readcount);
         if ioresult <> 0 then
            error('Errors on source disk.');
         blockwrite(output, data^, readcount, writecount);
         if ioresult <> 0 then
            error('Errors on target disk.');
         c:= c + readcount;
         disk:= disk + readcount;
         work(fileinfo.size, c);
         if readcount <> writecount then error('Unable to write to disk');
      end;
   clreol;
   close(input);
   close(output);
   dispose(data);
end;

procedure retrive(drive:char; path:string);
var
   setnum, disknum:word;
   diskdone, complete:boolean;
   newfile, store:file;
   cs:chksum;
   fileinfo, data:searchrec;
   d:buffer;
   c:longint;
   buffersize, readcount, writecount:word;
begin
   complete:= false;
   chdir(path);
   new(d);
   c:= 0;
   if ioresult <> 0 then
      error(path+' does not exist.');
   diskdone:= true;
   disknum:= 0;
   while not complete do
      begin
         if diskdone then
            begin
               clreol;
               disknum:= disknum + 1;
               if disknum > 1 then
                  close(store);
               diskdone:= false;
               write('Insert disk ', disknum, ' and press [ENTER].');
               readln;
               buffersize:= sizeof(arraybuf);
               if disknum = 1 then
                  begin
                     assign(cs, drive+':\check.sum');
                     reset(cs);
                     if ioresult <> 0 then error('No check sum file.');
                     read(cs, fileinfo);
                     close(cs);
                     assign(newfile, fileinfo.name);
                     rewrite(newfile, 1);
                     findfirst(drive+':\*.cat', archive, data);
                     if doserror = 18 then
                        begin
                           close(newfile);
                           erase(newfile);
                           error('Disk does not contain storage data.');
                        end;
                     assign(store, drive+':\'+data.name);
                     reset(store, 1);
                     setnum:= return(data.name, true);
                     if return(data.name, false) <> disknum then
                        begin
                           close(newfile);
                           erase(newfile);
                           error('Wrong disk.');
                        end;
                     writeln('File set number is: ', setnum);
                  end
               else
                  begin
                     findfirst(drive+':\*.cat', archive, data);
                     if doserror = 18 then
                        begin
                           close(newfile);
                           erase(newfile);
                           error('Disk does not contain storage data.');
                        end;
                     assign(store, drive+':\'+data.name);
                     reset(store, 1);
                     if setnum <> return(data.name, true) then
                        begin
                           close(newfile);
                           erase(newfile);
                           error('Disk is of a different set.');
                        end;
                     if disknum <> return(data.name, false) then
                        begin
                           close(newfile);
                           erase(newfile);
                           error('Wrong disk.');
                        end;
                  end;
            end;
         blockread(store, d^, buffersize, readcount);
         if ioresult <> 0 then
            begin
               close(newfile);
               erase(newfile);
               error('Errors on source disk.');
            end;
         blockwrite(newfile, d^, readcount, writecount);
         if ioresult <> 0 then
            begin
               close(newfile);
               erase(newfile);
               error('Errors on target disk.');
            end;
         c:= c + readcount;
         if writecount <> readcount then
            begin
               close(newfile);
               erase(newfile);
               error('Unable to write to disk.');
            end;
         if buffersize <> readcount then
            diskdone:= true;
         if fileinfo.size = c then complete:= true;
         work(fileinfo.size, c);
      end;
   clreol;
   close(newfile);
   close(store);
   dispose(d);
end;

var
   c1, c2:string;

begin
   if paramcount = 0 then
      help;
   if paramcount <> 3 then
      error('Incorect number of parameters.');
   c1:= paramstr(1);
   c2:= paramstr(2);
   case c1[1] of
      's', 'S' : store(paramstr(3), c2[1]);
      'r', 'R' : retrive(c2[1], paramstr(3));
   else
      error('Incorect parameters.');
   end;
   writeln('Complete!');
end.

{ ---------------  CUT ---------------- }

unit files;

interface

uses
   dos;

type
   filetype = string[12];
   {searchrec = record    This is how searchrec is defined in the DOS unit.
      Fill: array[1..21] of Byte;
      Attr: Byte;
      Time: Longint;
      Size: Longint;
      Name: string[12];
   end;  }
   filestack = ^ node;
   node = record
      fileinfo:searchrec;
      next:filestack;
   end;
   directory_tree = ^dnode;
   dnode = record
      dir:string;
      lower_dir:directory_tree;
      next:directory_tree;
   end;

procedure fill_filestack(var stack:filestack);
   {Fills stack of type filestack with all the file enteries in the
   current directory.  Includes directoies and hidden file types.}

procedure push_filestack(var stack:filestack; item:searchrec);
   {Pushes in alfa order a new node on a filestack.}

procedure fill_dirtree(dir:string; var tree:directory_tree);
   {Fills a tree sturcture with the directory structure using dir string
   as the root.}

implementation

procedure push_filestack(var stack:filestack; item:searchrec);
var
   temp:filestack;

   procedure insert(var stack, prev:filestack);
   begin
      if (stack = nil) then
         begin
            temp^.next:= stack;
            stack:= temp;
         end
      else
         if temp^.fileinfo.name > stack^.fileinfo.name then
            insert(stack^.next, stack)
         else
            if temp^.fileinfo.name < stack^.fileinfo.name then
               begin
                  if prev = stack then
                     begin
                        temp^.next:= stack;
                        stack:= temp;
                     end
                  else
                     begin
                        temp^.next:= stack;
                        prev^.next:= temp;
                     end;
               end;
   end;
begin
   new(temp);
   temp^.fileinfo:= item;
   insert(stack, stack);
end;

procedure fill_filestack(var stack:filestack);
var
   dirinfo:searchrec;
begin
   findfirst('*.*', anyfile, dirinfo);
   while doserror <> 18 do
      begin
         push_filestack(stack, dirinfo);
         findnext(dirinfo);
      end;
end;

procedure push(var head:directory_tree; item:string);
var
   temp:directory_tree;
begin
   new(temp);
   temp^.dir:= item;
   temp^.next:= head;
   head:= temp;
   head^.lower_dir:= nil;
end;

procedure fill_dirtree(dir:string; var tree:directory_tree);
procedure fill_dirlist(var head:directory_tree; directory:string; s:integer);
var
   place:directory_tree;
   dirinfo:searchrec;
   found:boolean;
begin
   writeln(directory);
   chdir(directory);
   findfirst('*.*', 16, dirinfo);
   while doserror = 0 do
      begin
         if (dirinfo.attr = 16) and ((dirinfo.name <> '..') and (dirinfo.name <> '.'))then
            begin
               push(head, fexpand(dirinfo.name));
               found:= true;
            end;
            findnext(dirinfo);
         end;
      if found then
         begin
            place:= head;
            while place <> nil do
               begin
                  fill_dirlist(place^.lower_dir, place^.dir, s+3);
                  place:= place^.next;
               end;
         end;
end;

var
   temp:directory_tree;
begin
   tree:= nil;
   fill_dirlist(tree, dir, 0);
   new(temp);
   temp^.dir:= dir;
   temp^.lower_dir:= tree;
   temp^.next:= nil;
   tree:= temp;
end;

end.

[Back to FILES SWAG index]  [Back to Main SWAG index]  [Original]