{ This program's target is to append more than one disk image to a disk
file what can be accessed by Miha Peternel's C64S.EXE or any other c64
emulators. This program is only for educ use coz Miha's emulator doesn't
allow reading from after 35th. track and without it this proggy is unusable.

  Theory of the appending:

  First, I'll talk about the discs on C64.
  There are 35 tracks and 21/19/18/17 sectors on every tracks.
  All of the sectors (called blocks) are beginning with two bytes:
     1st: the next track's number, if any
     2nd: and the sector's number.

  So if we convert the second, third, fourth disk we must rewrite its track
  numbers (e.g. if there was a following block on 1. track 18. sector,
  and this is the second disk, then we must update the first byte with
  35d+1d.)

  The directory area:
  12/01=16600h=
    0,1:   the following DIRECTORY BLOCK's track and sector
    02h-1fh:  1st. file
    22  3f    2nd.
    42  5f    3rd.
    62  7f    4th.
    82  9f    5th.
    a2  bf    6th.
    c2  df    7th.
    e2  ff    8th.

  When the following dir block is 00/ffh, then this is the latest block.
  And the unused blocks in the directory area contain 00/00 begin so we can
  simply check if the checked is a free dir block or not. When free, we
  can use it and the following some blocks, too; and the pointer in that
  block what has 00/ffh must be updated to its adress (12/sg). We can simply
  copy the second, third etc... directory areas (from 16600h) to the first
  free area BUT we must ALWAYS _ADD_ the beginning address (if the free space
  begun on 5h block, then its adress is 5th. block etc...). Ofcourse the
  file adress must be updated in the dir area, too; in the 2nd, 3rd etc...
  disks.

  Directory entry format:

  0:             type of file
  1,2:           the first data block's __track__ and sector address   !!!!!!!!!!
  03h-12h:       name (w/ a0 end)
  13h,14h:       only rel files!
  15h:           rel files only!
  16h-19h:       unused
  1ah-1bh:       the new file's track & sector adress when we overwrite it
                 w/ @s.
  1ch, 1dh:     number of blocks in the file.

  Type of file: 7th. bit: was it closed?

  The row of the blocks: as I mentioned before the LAST block always contains
  00 follow track and NUMBER OF BYTES WHAT ARE BELONGING TO THE FILE!! AS
  SECTOR NUMBER!!! (So you can understand why are there ffh in the latest
  dir block's following sector!)


  So the best way to append:
  1, COPY /b
  2, RESET (result)
1st. disk
  3, filepos to 16600h
  4, read two TEMPBYTE bytes: does the first OR the second contain 0?
  5, neither: filepos:=filepos+100h, goto 4.
  6, first is 0, second is not: last_dir_block:=filepos-2;
              filepos:=filepos+100h, goto 4. (search for first free block)
  7, both is 0: first_free_block:= filepos-2;
                to_add_to_all_dir_blocks:=(filepos-2 - 16600h) / 256;
  blocks_used_in_the_first_dir:=0;
2nd. disk:
  8, for i:=1 to 684 do begin  (there are 684 blocks w/ dir area ofkoz)
     filepos to 174848+i*256;
     read next track
     add 35d to the first byte, and write back  (Assuming we are working on the
                                    testdisk.d64 with its final size)
     end for;
  9, filepos to 174848+16600h
  10, aren't both bytes 0 here? yes: goto third disk. Third disk ofcoz
             EQUALS TO SECOND, recursively; but we have to filepos to
             2*174848+ values; add track numbers 2*35 etc...)

  11,
    if the_first_byte<>0 and the_second_byte<>0 then j:=8, else, if
        if the_first_byte=0 and the_second_byte<>0, then j:=the_second_byte;
          (reading ONLY so many dir entries what the bloc contains. There
          aren't big problmes if we fill one dir BLOCK entirely with
          unused dir entries coz in this positioning scheme we can only
          filepos to a brand new BLOCK's begin! So we won't write down this
          OR in the program, and before the NEXT we use simple i=?8 instead
          of i=?j)

     if blocks_used_in_the_first_dir=18 then abort('Too many dir entries!!');
     filepos to (16600h+(blocks_used_in_the_first_dir*256));
                ( position to the next free dir block )
     write(12h,blocks_used_in_the_first_dir+1)
                ( and soon we write out the position of the PHISICAL NEXT
                  block's adress to the begin two bytes of the new block.
                  If there wasn't any program errors, then )
     inc(blocks_used_in_the_first_dir);
     if blocks_used_in_the_first_dir=18 then abort('Too many dir entries!!');

     for i:=1 to 8  (there are 8 dir entries in every blocks)
        read 31 bytes
        add 35d to the 1st byte (counting from 0)
        filepos to (16600h+(blocks_used_in_the_first_dir*256)+(i-1)*31+2)
        write BACK the modified 31d bytes;  (we are on the beginning byte what
                                             we just read coz of re-fileposing)
     end for
     inc(blocks_used_in_the_first_dir)
     goto 10,  (read the following directory BLOCK)

third disk:
        filepos to (16600h+((blocks_used_in_the_first_dir-1)*256))
                (we write out to the last DIR BLOCK's beginning a 00 ff.
                OfCuZ we will update it if we'll have another disk!))


end prog}
type    one_dir_entry= array [0..31] of byte;

var blocks_used_in_the_first_dir, first_free_block:integer;
NUMBER_OF_FILES,j:INTEGER;
                        B1,b2:BYTE;
   I,
   _filepos,
   last_dir_block,
   to_add_to_all_dir_blocks,
   dir_read_actual_pos : longint;
   BYTEFILE1_IN,BYTEFILE2_IN,BYTEFILE3_IN,BYTEFILE4_IN,BYTEFILE5_IN,
   BYTEFILE6_IN,OUTFILE:FILE OF BYTE;
   _32_add_filepos,phisical_addr_of_entry,temp:longint;
    block,entry:longint; filename:string; tempint:integer;

   dir_entries_of_second_disk: array [1..144] of one_dir_entry;
   dir_entries_of_third_disk: array [1..144] of one_dir_entry;
   ptr_to_second_dir:byte;   { 1..144 }
   ptr_to_third_dir:byte;   { 1..144 }

begin
  NUMBER_OF_FILES:=PARAMCOUNT;

  ASSIGN(BYTEFILE1_IN,PARAMSTR(1));
  RESET(BYTEFILE1_IN);

  ASSIGN(BYTEFILE2_IN,PARAMSTR(2));
  RESET(BYTEFILE2_IN);

  ASSIGN(BYTEFILE3_IN,PARAMSTR(3));
  RESET(BYTEFILE3_IN);

  ASSIGN(OUTFILE,'TESTDISK.D64');
  REset(OUTFILE);                      { ********* }

  { now we fill dir_entries_of_second_disk }
seek(outfile,($16602+174848));
for i:=1 to 144 do begin
 for j:=0 to 31 do read(outfile,dir_entries_of_second_disk[i,j]);
  { and we automatically update the second byte }
 dir_entries_of_second_disk[i,1]:=dir_entries_of_second_disk[i,1]+35;
    end;  { reading second dir }

  { now we fill    dir_entries_of_third_disk }
seek(outfile,($16602+2*174848));
for i:=1 to 144 do begin
 for j:=0 to 31 do read(outfile,dir_entries_of_third_disk[i,j]);
  { and we automatically update the second byte }
 dir_entries_of_third_disk[i,1]:=dir_entries_of_third_disk[i,1]+70;
    end;  { reading third dir }

 { now we search for an empty dir entry in the first dir. Read my remarks
 in COPY2DSK.PAS! }

_filepos:=$16602;
ptr_to_SECOND_dir:=1;
ptr_to_third_dir:=1;
block:=0;    { counting the block }
entry:=1;    { counting the entry in all blocks }


repeat
 seek(outfile,_filepos);
 _32_add_filepos:=_filepos;
 read(outfile,b1);                      { searching for a unused or deleted
                                          file in first dir. We'll put EACH
                                          entries from 2nd and 3rd disk
                                          _separately_ to first dir- this is
                                          the most dir size-saving system.
                                          So where there are free space, we
                                          fill it with a new entry }
 if (b1=0) or (b1=$80) then begin
              phisical_addr_of_entry:=_filepos;
              _filepos:=$16600+block*256;
              seek(outfile,_filepos);
              read(outfile,b2);
              read(outfile,b2);
              if b2=0 then begin  { this is the worst case: we have the first
                                    empty entry in an unused block! }
                _filepos:=$16600+(block-1)*256;
                   { always the PREVIOUS block is the last-but-one block! }
                b2:=18;
                write(outfile,b2);
                b2:=block;
                write(outfile,b2);
                          end;
              seek(outfile,phisical_addr_of_entry); { and now: search for a
                                                      non-empty entry in
                                                      2nd dir, and copy! }
              if (dir_entries_of_second_disk[ptr_to_second_dir,0]>80)
                 then    { yes, we have found a converted 2nd entry! }
       for i:=0 to 29 do write(outfile,dir_entries_of_second_disk[ptr_to_second_dir,i]);
              inc(ptr_to_second_dir);   { and read the next entry if there are }
  end; { if we found an unused entry in the first dir }
 _filepos:=_32_add_filepos+32;
 inc(entry);
 if entry=9 then begin
                 inc(block);
                 entry:=1;
                 end;


until (dir_entries_of_second_disk[ptr_to_second_dir,3]=0) or (_filepos>=96256)
 or (dir_entries_of_second_disk[ptr_to_second_dir,0]=0);
  { we continue copying until we reach a dir entry in second dir where the
    first letter of the name is a 0. This means that this is the end of the dir. }
if _filepos>=96256 then begin
      writeln(' Argh... Not enough dir entry... DELETE testdisk.d64!');
                        exit;
                        end;


repeat
 seek(outfile,_filepos);
 _32_add_filepos:=_filepos;
 read(outfile,b1);                      { searching for a unused or deleted
                                          file in first dir. We'll put EACH
                                          entries from 2nd and 3rd disk
                                          _separately_ to first dir- this is
                                          the most dir size-saving system.
                                          So where there are free space, we
                                          fill it with a new entry }
 if (b1=0) or (b1=$80) then begin
              phisical_addr_of_entry:=_filepos;
              _filepos:=$16600+block*256;
              seek(outfile,_filepos);
              read(outfile,b2);
              read(outfile,b2);
              if b2=0 then begin  { this is the worst case: we have the first
                                    empty entry in an unused block! }
                _filepos:=$16600+(block-1)*256;
                   { always the PREVIOUS block is the last-but-one block! }
                b2:=18;
                write(outfile,b2);
                b2:=block;
                write(outfile,b2);
                          end;
              seek(outfile,phisical_addr_of_entry); { and now: search for a
                                                      non-empty entry in
                                                      2nd dir, and copy! }
              if (dir_entries_of_third_disk[ptr_to_third_dir,0]>80)
                 then    { yes, we have found a converted 2nd entry! }
       for i:=0 to 29 do write(outfile,dir_entries_of_third_disk[ptr_to_third_dir,i]);
              inc(ptr_to_third_dir);   { and read the next entry if there are }
  end; { if we found an unused entry in the first dir }
 _filepos:=_32_add_filepos+32;
 inc(entry);
 if entry=9 then begin
                 inc(block);
                 entry:=1;
                 end;


until (dir_entries_of_third_disk[ptr_to_third_dir,3]=0) or (_filepos>=96256)
 or (dir_entries_of_third_disk[ptr_to_third_dir,0]=0);
  { we continue copying until we reach a dir entry in third dir where the
    first letter of the name is a 0. This means that this is the end of the dir. }
if _filepos>=96256 then begin
      writeln(' Argh... Not enough dir entry... DELETE testdisk.d64!');
                        exit;
                        end;

                  { INC SECOND AND THIRD DISKS' BLOCK STRING PTR }
for i:=1 to 684 do begin  {there are 684 blocks w/ dir area oFCuZ} {SECOND}
   if (i<358) or (i>358+18) then begin   {we don't modify directory blocks'
                                 begin coz we won't use them anymore!}
     _filepos:=174848+(i-1)*256;
     seek(outfile,_filepos);
     read(outfile,b1);
     b1:=b1+35;
     _filepos:=filepos(outfile)-1;    { position back to the first byte of all
                                      stored blocks }
     seek(outfile,_filepos);
     write(outfile,b1);
   end; {if}
     end;  { for }

for i:=1 to 683 do begin  {there are 684 blocks w/ dir area oFCuZ} {THIRD}
   if (i<358) or (i>358+18) then begin   {we don't modify directory blocks'
                                 begin coz we won't use them anymore!}
     _filepos:=2*174848+(i-1)*256;
     seek(outfile,_filepos);
     read(outfile,b1);
     b1:=b1+70;
     _filepos:=filepos(outfile)-1;    { position back to the first byte of all
                                      stored blocks }
     seek(outfile,_filepos);
     write(outfile,b1);
   end; {if}
     end;  { for }

close(outfile);
end.



OR I:=1 TO 174848 DO BEGIN    { copying the first disk }
    READ(BYTEFILE1_IN,B1);
    WRITE(outfile,B1);
end;

FOR I:=1 TO 174848 DO BEGIN    { copying the second disk }
    READ(BYTEFILE2_IN,B1);
    WRITE(outfile,B1);
end;

FOR I:=1 TO 174848 DO BEGIN    { copying the third disk }
    READ(BYTEFILE3_IN,B1);
    WRITE(outfile,B1);
end;              }