DataMuseum.dk

Presents historical artifacts from the history of:

RC4000/8000/9000

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about RC4000/8000/9000

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download

⟦a27f5f3ad⟧ TextFile

    Length: 165120 (0x28500)
    Types: TextFile
    Names: »tincsave«, »vko«

Derivation

└─⟦00964e8f7⟧ Bits:30007478 RC8000 Dump tape fra HCØ.
    └─⟦b2ec5d50f⟧ 
        └─⟦this⟧ »tincsave« 
        └─⟦this⟧ »vko« 

TextFile

incsave=algol list.no xref.no blocks.no

begin
  message vk 1982.02.03 incsave;
  boolean last,total,std,list,outp,sys,savenotok;
  integer outres,date,i,vksegm,psegm,c2size;
  long array input(1:2);
  real array outarr(1:3);
   long array tapename(1:2),ptapename(1:2),t1tapename(1:2),resname(1:2);

  zone zhelp(1,1,stderror);
  procedure openout;
  begin
    long array outname(1:2);
    outp:=true;
    outname(1):=input(1);outname(2):=input(2);
    fpproc(29)stack current out:(0,out,outarr);
    outres:=201;
    fpproc(28)connect out:(outres,out,outname);
    if outres <> 0 then
    begin
            outp:=false;
      fpproc(30)unstack out:(0,out,outarr);
      write(out,<:<10> connect error=  :>,outres);
      goto halt;
    end;
  end;
  procedure closeout;
  begin
     write(out,<:<10>:>);
    if outp then
    begin
      fpproc(34)close up:(0,out,25);
      fpproc(79)terminatezoe:(0,out,0);
      fpproc(30)unstack out:(0,out,outarr);
    end;
  end;
\f


procedure  vksortproc(param, keydescr, names, eof, noofrecs,
                    result, explanation);
value  eof;
real  eof;
integer array  param, keydescr;
real array  names;
integer  noofrecs, result, explanation;
comment
\f


  Algol fortran standard procedure  mdsortproc                 page  1




  Purpose.

    Mdsortproc, merge_disc_sorting_procedure, is a procedure,
    intended for fast sorting of one backing storage area.
    The procedure can be called from a program coded in algol or
    fortran for RC 4000, RC 6000, and RC 8000.



  Function.

    The procedure sorts a backing storage file holding records of either
    fixed or variable length, using backing storage throughout.
    The basic sorting method, is the merge technique:
    Sorted strings, as long as possible, are generated by internal sor-
    ting during the first reading of the input file.
    After that, these strings are merged repeatedly until only one sor-
    ted string is left.

    The procedure will try to minimize the sorting time by variation of
    mergepowers, blocklengths, use of single- or double-buffering, and
    by utilization of two disc-stores, if available.
    The procedure needs in total a backing storage area of about twice
    the size of the data to be sorted.
    It can be specified that the input file shall be cleared, so its
    area can be used for the merge.
    The free core, when the procedure is called, must be more than 
    about 10000 halfwords, depending on the blocklengths and record-
    lengths specified.
    The value of 10000 is valid for blocklengths up to 2 segments.
    The sort can use any amount of free core to speed up the sorting
    and room for a work file on two different discs will reduce the
    time for input output.
\f


  Algol fortran standard procedure  mdsortproc                 page  2




  Call.

    mdsortproc      (param, keydescr, names, eof, noofrecs,
                    result, explanation)

    param(1:7)      (call value, integer array)
                    This array holds various parameters of type integer
                    and type boolean, describing the files and the
                    records.

    param(1)        segsperinblock.
                    Blocklength of the input file, given as a number
                    of segments. 1 <= segsperinblock <= 40.
                    Supplied by sq system if content = 21.

    param(2)        clearinput.
                    1:  The input file is cleared, and its area can be
                        used for the merge.
                    0:  The input file must not be cleared.

    param(3)        segsperoutblock.
                    Blocklength of the final output file, given as a
                    number of segments. 1 <= segsperoutblock <= 40.
                    If param(3) = 0 , segsperoutblock:= segsperinblock.

    param(4)        fixedlength.
                    1:  Fixed recordlength. Inrec6/outrec6 are used.
                    0:  Variable recordlength. Invar/outvar are used.
                    2:  variable recordlength but no checksum.

    param(5)        maxlength.
                    The maximum length of variable length records, and
                    the length of fixed length records, measured in 
                    halfwords.
                    Maxlength >= 2 and maxlengh <= segsperinblock * 512
                    and maxlength <= segsperoutblock * 512.
                    Maxlength must be even.
                    It is important for the efficiency of the sort
                    that maxlength reflects the real maximum length
                    of variable length records.

    param(6)        noofkeys.
                    The number of keyfields in the sorting key.
                    1 <= noofkeys <= maxlength and <= 169.

    param(7)        concerns the reaction on resource troubles.
                    0:  Resource troubles will not stop the execution,
                        the procedure returns with result > 1.
                  <>0:  Resource troubles causes runtime alarm.
\f


  Algol fortran standard procedure  mdsortproc                 page  3




    keydescr(1:     (call value, integer array)
    noofkeys, 1:2)  The description of the sorting key.
                    Keyfield n is specified as: +/- type, position,
                    in keydescr(n, 1:2).
                    The type ranges from 1 to 5, indicating:  signed
                    halfword, integer, long, real, or abshalfword.
                    The sign of the type specifies the sequencing:
                    + for ascending, and - for descending order.
                    The position of the keyfield is specified as the
                    number of the last halfword in the field, as for 
                    algol field variables.
                    The position may not excede 2047.
                    The entire keyfield must be within a maximum length
                    record.
                    The length of variable length records must not be
                    less than the position of keyfield 1, the highest
                    priority keyfield.
                    records having equal values in all keyfields are
                    sorted according to their occurrence in the input 
                    file, i.e. their mutual order is not changed.
                    In connection with very long records (maxlength=
                    param(5) >= 2046) the facility is switched off.

    names(1:6)      (call and return value, real array)
                    Contains 3 file and disc names.

    names(1:2)      inputfile.
                    The name of a backing storage area.
                    The procedure asumes that the size of the area re-
                    flects the amount of data to be sorted.

    names(3:4)      outputfile.
                    If names(3) = real<::> then the name of the output-
                    file is returned in names(3:4), otherwise the name
                    given is used for the final output file.
                    An existing file of this name on scope temp is
                    cleared without warning, just before the end.
                    The sort is not able to use the resources of such
                    a file.

    names(5:6)      outdisc.
                    If names(5) = real<::> then the output disc is
                    selected according to the most efficient strategy,
                    otherwise the disc specified is used.
\f


  Algol fortran standard procedure  mdsortproc                 page  4




    eof             (call value, real)
                    If the parameter noofrecs is negative, then the
                    end of the input file is indicated by a record
                    holding the bitpattern given by eof in the first
                    4 halfwords of the userpart. Halfword 1 to 4 in
                    case of fixed length and halfword 5 to 8 in case
                    of variable length records.
                    The final output file is terminated by an end
                    of file record of maximum length in this case.

    noofrecs        (call and return value, integer)
                    If noofrecs is non negative, then the number of
                    records in the input file is given by the value of
                    noofrecs and an eof record is not created.
                    The number of sorted records is returned in any
                    case in this parameter.
                    With an sq file noofrecs <= 0 means that noofrecs
                    is supplied by the sq system, noofrecs > 0 means
                    that only this number of records are to be sorted.

    result          (return value, integer)
                    The value of result specifies the result of the
                    call of the procedure.
                    In general, resource problems will yield a result
                    different from 1, whereas errors concerning the
                    parameters or hard errors will stop the execution
                    by a runtime alarm.
                    If param(7) <> 0 only result = 1 will occur, the
                    other results are transformed to alarms.

    explanation     (return value, integer)
                    The value of this parameter should give a further
                    explanation of result. See the next section.


  Sq system files.

    If the content field of the catalog entry of the input file
    is equal to 21, it is supposed that the file conforms to the
    conventions of the sq file system.
    The output file will be created as an sq file as well.



  Results.

    result  explanation             comment

    1       segments output         the sort was ok
    2       -lacking core halfwords not sufficient core
    3       see alarm disc          not sufficient backing storage
    4       see alarm out disc      backing store specified by names
                                    (5:6) does not exist or has too
                                    few resources.

    Results > 1 are only given if param(7) = 0.

    The parameter noofrecs will contain the number of sorted records
    if result = 1 , otherwise it is unchanged.
    The output file will, provided result = 1, be cut to the minimum
    size, and tail(6) of the catalog entry will contain the same
    value as noofrecs, if not sq file.
\f


  Algol fortran standard procedure  mdsortproc                 page  5




  Requirements.

    The available amount of core storage before the call of the proce-
    dure must satisfy the condition:

      free_half_words
                  > 7000
                  + 512*(segsperinblock + segsperoutblock)
                  + 4*maxlength + 24*noofkeys.

    The procedure requires as working areas two disc files of the
    size of the input file.
    This means in the case when the input file is removed that
    the procedure must be able to create one work file of that size.

    If the input file is not removed the procedure must be able
    to create two work files of the size of the input file.
    If an output disc is specified this disc must be able to
    hold the final output file.
    already at the beginning of the procedure it is checked that 
    the output disc is capable of holding a file of the size of the
    input file. (this is of course the case if the inputfile is
    placed on the disc specified and has to be removed).
    the blocking of records may be changed by the sorting, so the
    output file may have a greater size than the input file.
    Work files are kept at minimum size by concatenation of the
    records without regards to block limits.

    The procedure needs 2 catalog entries, 2 area processes, and
    1 message buffer. So, the job process should at least be the owner
    of 4 area processes, and 2 message buffers.
    But it is recommended to have a greater number of message buffers,
    (10 to 20), especially in the case of a sort of small records, 
    (about 2 to 20 halfwords), with great core size.



  Variable length records.

    The sum check facility of invar is used during the reading of the
    input file if param(4) = 0 (invar with checksum control).
    The record length must not excede maxlength. 
    The minimum record length is given by the greatest of the two val-
    ues:  4 (if noofrecs < 0 then 8) and keydescr(1, 2).
    Thus some of the keyfields of a short record may in fact be situ-
    ated outside the record.
    Such a record is sorted as if all the bits of keyfields outside 
    the record were equal to zero.
\f


  Algol fortran standard procedure  mdsortproc                 page  6




  Alarms.

    Parameter errors and hard file errors will stop the run with a run
    time alarm.

    alarmtext   integer             comment

    param       param number        error at param(param number)
    keyfield    keyfield            illegal position or type of keyfield
                                    <integer>.
    create      monitor result      abnormal result in call of the mon-
                                    itor procedure create entry.
    lookup      monitor result      abnormal result from lookup entry.
                                    This alarm will normally indicate
                                    that names(1:2) does not specify a
                                    catalog entry.
    change      monitor result      abnormal result in call of change
                                    entry. Should not occur.
    rename      monitor result      it is impossible to rename the final
                                    output file to names(3:4).
    remove      monitor result      abnormal result in call of remove
                                    entry. The alarm will normally con-
                                    cern the original input file.
    infile      tail(1)             names(1:2) does not point to a catalog
                                    entry describing an area.
    r.length    record length       variable length record of a length
                                    greater than maxlength, less than key-
                                    descr(1, 2), or less than 8 if eof used.
    passes      20                  the sort could not be done in 20 mer-
                                    ging passes. This alarm should never
                                    occur.
    reccount    record count        this is a hard error or a programming
                                    error. The counts of records in the
                                    first pass and the last, are not 
                                    equal, the last count is shown.
    size        -lacking halfwords  not enough core.
    disc        -lacking entries    too few entries in main catalog.
                segments            not enough segments, the value
                                    of segments is the size of
                                    one workfile.
    out disc    -1                  the wanted output disc is not
                                    mounted.
                segments            not room for one workfile on the
                                    wanted output disc.
    trap        passnumber          normally spill in key comparison.
    nrecs sq    noofrecs            param noofrecs > records in sq file.

    The alarms: size, disc and out disc (resources) will only be given
    in case param(7) <> 0, otherwise the corresponding results, 2 to 4,
    with explanation will be given.
    In addition, index alarms may occur, if the parameter arrays are
    incorrectly declared, and alarms from opensq or stderror may occur, 
    if file or record formats are illegal or in case of hard errors.
    Alarms, with the exception of index alarms, are preceded by the
    text, ***mdsortproc alarm:.

    The alarm r.length, and stderror alarms occurring during the rea-
    ding of the input file are also preceded by a line, specifying the
    number of input records accepted before the error was detected.
\f


;
begin
  boolean
    fixedlength;

  integer
    bytes_per_inblock,
    bytes_per_outblock,
    content,
    discstores,
    freebytes,
    i,
    maxkeyposition,
    maxlength,
    maxlength_plus_four,
    messbufsforinp,
    min_segs_per_block,
    noofkeys,
    outbytes,
    outsegment,
    pass,
    passes,
    recs,
    recsout,
    segsin,
    segsoutzero,
    segsperinblock,
    segsperoutblock,
    shares,
    shortclock,
    strings1;
  real time;


  integer array
    in_segs, merge_power, segsout(1:20);

  real array
    sortfiles(1:4);
comment *************************************;
integer resultsq;
procedure opensq(p1,p2,p3,p4);
zone p1; string p2; integer p3,p4;
begin
  write(out,<:*******opensq call********* :>);
  goto returnfromdiscsort;
end;
comment **************;


comment -test-<

procedure  printkey(i1, i2, r) -test-<
value               i1, i2     -test-<
integer             i1, i2     -test-<
real array                  r  -test-<
begin
  integer  i, pos -test-<
  boolean field  bfld -test-<
  integer field  ifld -test-<
  long    field  lfld -test-<
  real    field  rfld -test-<

  pos:= write(out, <:<10>key :>, << ddddd>, i1, i2, <:::>) -test-<
  for i:= 3 step 2 until noofkeys*2+1 do
  begin
    if pos > 100 then
       pos:= write(out, <:<10>        :>) -test-<
    bfld:= ifld:= lfld:= rfld:= keydescr(i+1) -test-<
    pos:= pos + (case abs keydescr(i) of (
      write(out, << -dddd>, r.bfld extract 12),
      write(out, << -ddddddd>, r.ifld),
      write(out, <<-dddddddddddd>, r.lfld),
      write(out, <<-ddddddddddd>, r.rfld),
      write(out, << -dddd>, r.bfld extract 12))) -test-<
  end -test-<
  write(out, <:<10>:>) -test-<
end  printkey ;

\f


procedure  print_rec(recno, rec);
value  recno; integer  recno; real array  rec;
comment

  prints recno and the keyfields of rec;
begin
  integer  i, pos;
  boolean field  bfld;
  integer field  ifld;
  long    field  lfld;
  real    field  rfld;

  pos:= if pass = 0 then
           write(out, <:<10>no::>, <<ddddddd>, recno, <:  key::>)
        else
           write(out, <:<10>key::>);
  for i:= 3 step 2 until noofkeys*2 + 1 do
  begin
    bfld:= ifld:= lfld:= rfld:= keydescr(i+1);

    if pos > 62 then  pos:= write(out, <:<10>    :>);

    pos:= pos + 
    (case (abs keydescr(i)) extract 2 + 1 of (
    <* 4   *> write(out, <<-dddddddd.dddd'-dd>, rec.rfld),
    <* 1,5 *> write(out, <<  dddd>, rec.bfld extract 12),
    <* 2   *> write(out, <<    -ddddddd>, rec.ifld),
    <* 3   *> write(out, <<  -ddddddddddddddd>, rec.lfld)));
  end  print keyfields;
  write(out, <:<10>:>);
end  print_rec;



procedure  print_zsort(zsort);
zone  zsort;
comment

  prints the two last compared records in zsort.
  the comparison must have been done by outsort or lifesort;
begin
  integer  i;
  integer field  recnumber;
  integer array  ia(1:20), bases(1:2);

  recnumber:= maxlength + 2;

  getzone6(zsort, ia);
  system(5, ia(2) - 2, bases);

  for i:= 1, 2 do
  begin
    ia(14):= bases(i); <* recordbase *>
    setzone6(zsort, ia);
    print_rec(zsort.recnumber, zsort);
  end  print the two records;
end  print_zsort;
\f


procedure  alarm(text, int);
value  text, int;
integer  text, int;
comment

  this is the common alarm and error procedure.
  it removes the workfiles.
  the integer text selects the alarmtext, and the integer int
  is the alarm integer.
  if text >= 100 return is performed to docerror.
  if text >= 12 and <= 14 return may be performed with result and
  explanation by a jump to return_from_discsort, otherwise
  system is called by a jump to the bottom of procedure
  discsort in order to get a simple alarm address.
  the string value of the text is transmitted in
  sortfiles(1), and the integer in segsin.
;
begin
  integer  i;

  for i:= 1, 3 do  clear_file(sortfiles, i);

  if text >= 12 and text <= 14 then
  begin
  comment    return with result <> 1 depending on param(7);
    if param(7) = 0 then
    begin
      result:= text - 10;
      explanation:= int;
      goto return_from_discsort;
    end  continuation wanted;
  end  text 12 to 14;

  write(out, <:<10><10>***mdsortproc alarm:<10>:>);
  if text = 9 or text = 100 then
    write(out, <:<10>   accepted records:  :>, recs, <:<10>:>);

  if text < 100 then
  begin
  comment    not called from docerror;

  sortfiles(1):= real (case  text  of(

    <:<10>param   :>,
    <:<10>keyfield:>,
    <:<10>create  :>,
    <:<10>lookup  :>,
    <:<10>change  :>,

    <:<10>rename  :>,
    <:<10>remove  :>,
    <:<10>infile  :>,
    <:<10>r.length:>,
    <:<10>passes  :>,

    <:<10>reccount:>,
    <:<10>size    :>,
    <:<10>disc    :>,
    <:<10>out disc:>,
    <:<10>trap    :>,

    <:<10>nrecs sq:>));

  segsin:= int;

comment -test-< system(9, segsin, string sortfiles(1));
  goto  alarmcall;
end  not called from docerror;
end  alarm;

\f





procedure  clear_file(name, i);
value  i; integer  i; real array  name;
begin
  zone z(1, 1, stderror);
  open(z, 0, string name(increase(i)), 0);
  monitor(48, z, 0, in_segs); <* remove entry *>
end  clear_file;






procedure  docerror(z, s, b);
zone  z;
integer  s, b;
comment

  the procedure calls alarm to have the sortfiles removed and
  the alarm headline printed, and calls stderror;
begin
  alarm(100 + pass, 0);

  stderror(z, s, b);
end  docerror;

\f



procedure  endoffilerec(zout);
zone  zout;
comment

  note that this procedure finishes the sort by a jump to the
  label return_from_disc_sort.

  if the parameter noofrecs < 0, the procedure creates a
  record of the maximum length holding the bitpattern given by eof
  in the first 4 bytes of the userpart.
  if content is not zero, the remaining part of the block, or per-
  haps a new block is filled with integers of the value -1.
  remember that the final output is super blocked
  if made in the mergephase;

begin
  integer  i, maxlength, remaining, remaining_blocks, segments;
  integer array  ia(1:20);
  integer field  ifld;
  real array field  raf;

  if recs <> recsout then  alarm(11, recsout);

  if noofrecs < 0 then
  begin
  comment  create a maximum length eof record;

  maxlength:= param(5); <* use the original maxlength *>

  ifld:= outrec6(zout, 0) mod bytes_per_out_block;
  if ifld < maxlength then
  begin
    outrec6(zout, ifld);
    for ifld:= ifld step -2 until 2 do  zout.ifld:= 0;
  end  not room for maxlength in current block;
  outrec6(zout, maxlength);

  for ifld:= 2 step 2 until maxlength do  zout.ifld:= 0;

  if fixedlength then  zout(1):= eof
  else
  begin
    ifld:= 2;
    zout.ifld:= maxlength;
    zout(2):= eof;
    checkvar(zout);
  end  variable length;

  end  noofrecs < 0;
\f


comment    find the size of the file;

  for i:= 1 step 1 until 10 do  ia(i):= 0; <* tail for changeentry *>

  remaining:= outrec6(zout, 0);
  getposition(zout, 0, segments);

  if pass = 0 then  segments:= segments + segs_per_outblock
  else
  begin
  comment    superblocking is used;
    remaining_blocks:= (remaining - 2)//bytes_per_out_block;
    remaining:= remaining - remaining_blocks * bytes_per_out_block;
    segments:= segments + segs_out(pass) - remaining_blocks * segs_per_out_block;
  end  after merge;

  if content <> 0 then
  begin
  comment
    fill the remaining part according to bs and sq system;

    outrec6(zout, remaining);
    for ifld:= 2 step 2 until remaining do
      zout.ifld:= -8388608;
    ia(7):= segments // segs_per_out_block - 1; <* blocknumber *>
    ia(8):= bytes_per_out_block - remaining;
    ia(9):= content shift 12 add segs_per_out_block;
    remaining:= 0;
    if content = 21 then
    begin
      integer array field headpart;
      setposition(zout, 0, 0);
      headpart:= 0;
      invar(zout);
      i:= zout.headpart(1);
      setposition(zout, 0, 0);
      swoprec6(zout, i);
      headpart:= zout.headpart(3);
      headpart:= zout.headpart(1);
      resultsq:= 1;
      ia(6):= shortclock:= systime(7, 0, time);
      for i:= 2 step 1 until 7 do
      zout.headpart(i):= case i -1 of
        (1,
         recs,
         ia(7),
         ia(8),
         0,
         shortclock
        );
      checkvar(zout);
      ia(7):= ia(8):= 0;
    end sq file;
  end  bs system;

  close(zout, true);

  ia(1):= explanation:= segments - remaining//512;
  ia(if content = 21 then 10 else 6):= noofrecs:= recs;

  i:= monitor(44, zout, 0, ia); <* change entry *>
  if i <> 0 then  alarm(5, i);

comment    rename the file or return workname;

  if names(3) <> real<::> then
  begin
    raf:= -2*4;
    for i:= 3 step 1 until 4 do  ia.raf(i):= names(i);
    i:= monitor(46, zout, 0, ia); <* rename entry *>
    if i = 3 <* the name exists already *> then
    begin
      clear_file(names, 3);
      i:= monitor(46, zout, 0, ia); <* repeat rename *>
    end  i = 3;
    if i <> 0 then  alarm(6, i);
  end  rename
  else
  begin
  comment    return workname;
    getzone6(zout, ia);
    raf:= 2 - 2*4;
    for i:= 3 step 1 until 4 do  names(i):= ia.raf(i);
  end  return name;

  result:= 1;
  goto return_from_discsort;

end  endoffilerec;

\f



procedure  endoutstring(zout, out_base, block_size);
value    block_size;
zone  zout;
real array field  out_base;
integer  block_size;
comment

  the procedure outrecs a string chaining record of 6 bytes,
  pointing to the start of the current outstring.
  the first 4 bytes contain the values of the variables outsegment
  and outbytes, specifying the position of the preceding chain
  record.
  the last two bytes hold the value of recsout, specifying the number
  of records in the current outstring.
  outsegment and outbytes are updated to point to the new chain
  record, and recsout is set to zero.

  global quantities:

    outsegment          the segment number of the block holding the
                        last created string chaining record.
    outbytes            the number of bytes preceding the chain record
                        in this block.
    recsout             the number of records in the current outstring.
;
begin
  integer  i, segment;
  integer field  new_base;

  getposition(zout, 0, segment);

  new_base:= out_base;
  for i:= outsegment, outbytes, recsout do
  begin
    if new_base >= block_size then
    begin
      outrec6(zout, block_size);
      new_base:= 2;
    end  change output block
    else
      new_base:= new_base + 2;
    zout.new_base:= i;
  end  for i;

comment -test-< write(out, <:<10>test 14 , outsegment, outbytes,:>,
  <: recsout: :>, outsegment, outbytes, recsout);

comment    set outsegment, outbytes, recsout for the new string;

  outsegment:= out_base // 512 + segment;
  outbytes  := out_base mod 512;
  recsout:= 0;

  out_base:= new_base;
end  endoutstring;

\f



procedure  errorinoutfile(z, s, b);
zone  z;
integer  s, b;
comment
  
  this procedure is used as the blockprocedure of the output zones.
  if not end of document then docerror is called.
  else alarm is called;
begin

  if s shift (-18) extract 1 <> 1 then  docerror(z, s, b);

  alarm(13, segsin); <* may give result 3 *>
end  errorinoutfile;

\f



procedure  select_merge_strategy;
comment

  this procedure selects the most efficient strategy for the merge 
  under the constraints chosen.
  the quantities, which can be altered, are the number of passes, the
  mergepowers and the blocklengths corresponding to each pass,
  and the number of shares to be used for input/output.

  important global quantities:

    discstores          if discstores=2 then the transfertime can be
                        cut to the half by the use of doublebuffering.
    freebytes           the amount of core available for buffers.
                        a reasonable amount of room for programsegments
                        and variables has been subtracted in advance.
    passes              at entry, the value of passes defines the pos-
                        sible numbers of passes:
                        0:  any number of passes is possible.
                        1:  only an odd number of passes is possible.
                        2:  only an even number of passes is possible.
                        at return, passes contains the selected number
                        of merging passes.
    recs                the total number of records.
    segsin              the number of segments of the input file.
    segsperoutblock     blocklength of the final output file.
    shares              the selected number of shares for input/output.
    mergepower(1:20)    the selected mergepowers for the merge passes.
    insegs(1:20)        input blocklengths for merging passes.
    segsout(1:20)       output blocklengths for merging passes.
    strings1            the number of strings generated in pass 0.
;
begin
  integer  test_passes, test_shares,
    bytes_per_in_seg, bytes_per_power, bytes_per_out_seg,
    first_pass, pass_step,
    last_maxpower, maxpower;

  real  great, min_time, time, time_best_passes;

  integer array  test_mergepower, test_in_segs, test_segs_out(1:20);
\f



boolean procedure  find_powers;
comment

  given a specific number of testpasses, the string generation pass not
  counted, this procedure will, if sensible, return a series of
  test_mergepowers.
;
begin
  integer  i, last_maxstrings, maxstrings, p;

  maxstrings:= p:= if test_passes > 1 then  1
                   else
                   if strings1 < last_maxpower then  strings1
                   else          last_maxpower;

  for i:= 1 step 1 until test_passes do  test_mergepower(i):= p;

  find_powers:= true;

  if maxstrings >= strings1 then  goto return;

  last_maxstrings:= 0;
  for p:= p + 1 while last_maxstrings < maxstrings do
  begin
    last_maxstrings:= maxstrings;
    for i:= 1 step 1 until test_passes do
      if p <= (if i < test_passes then  maxpower else  last_maxpower) then
      begin
        test_merge_power(i):= p;
        maxstrings:= maxstrings // (p-1) * p;
        if maxstrings >= strings1 then  goto return;
      end  mergepower can be increased to p;
  end  for p;

  find_powers:= false;

return:
end  find_powers;
\f




real 
procedure  segs_and_time;
comment
  given a set of test_mergepowers, the procedure will find the
  best blocklengths.
  the procedure calculates the time needed for the merge, and if this
  time is less than mintime, it is stored in mintime, and the
  relevant values are saved in the global variables used to control
  the merge.
  the time calculation is based upon empirical data for the disc, as
  well as for the program.

;
begin
  integer  i, max_buffer_bytes,
    p, p_times_bytes_in, segments_in, segments_out,
    test_segments_in, test_segments_out;

  real  time, disc_for_pass, disc_for_in, disc_for_out,
    test_time,
    accesstime, transfertime, cpu_for_pass;
\f



comment
  define empirical time constants in milliseconds:

    for the disc store the following approximation is used:
    disctimepersegment = accesstime/segsperblock + transfertime.

    if only 1 discstore or only 1 share is used, the times for input
    and output are added, otherwise the maximum value is used;

  accesstime  := 30;
  transfertime:= 25/12 <* 12 = some mean track length *>;

comment
    if several disc store types are used, the time constants should
    be set according to a device type in the external process
    for the disc storage device.

    it is very difficult to calculate the time used for the disc
    in a realistic manner. it should f.ex. be taken into account
    that the disc-controller may allow parallel head positioning,
    but not parallel data transfers, also
    the transfertime may be greater if shorter disc slices chained
    together are physically spread over the disc.

    the cpu time is estimated as a linear function of the number of
    records and the number of segments.

    the following time constants should not be quite unrealistic:
    but the machinetype should be fetched from the monitor and the
    timeconstants set according to the speed of the cpu.

      cpu_per_record      :  2.0
      cpu_per_segment     :  3.2
;

  cpu_for_pass     :=   recs * 2.0 + segsin * 3.2;

comment
    in addition to the times mentioned above, 2 seconds are added per
    merging pass, and for 2 shares 10 percent is added to total time
    to cover a persumed interference between the discs and the cpu.
    another reason for this punishment of double buffering has been
    the fact that the total load of the machinery, i.e. the sum of
    the individual working times of discs and cpu, is greater with 
    double buffering due to smaller blocklengths or more passes;
\f


  time:= 0;
  for i:= 1 step 1 until test_passes do
  begin
  comment  set some usefull variables;
    p:= test_merge_power(i);
    p_times_bytes_in:= bytes_per_in_seg * p;
    max_buffer_bytes:= free_bytes - bytes_per_power * p;
    disc_for_pass:= great;
    test_segments_in:= min_segs_per_block;

calc_segments_out:
    test_segments_out:=
      (max_buffer_bytes - test_segments_in * p_times_bytes_in)
      // bytes_per_out_seg;

    if i = test_passes <* the last pass *> then
       testsegmentsout:= 
         (if content = 21 and testsegmentsout > segsperoutblock then
          segsperoutblock else testsegmentsout)
                           // segs_per_out_block * segs_per_out_block;

    if test_segments_out >= min_segs_per_block then
    begin
    comment    calculate the disctime for 1 segment;
      disc_for_in := access_time/test_segments_in  + transfer_time;
      disc_for_out:= access_time/test_segments_out + transfer_time;

      test_time:=
        if test_shares = 1 or discstores = 1 then
           disc_for_in + disc_for_out
        else
        if disc_for_in > disc_for_out then  disc_for_in
        else
           disc_for_out;

      if disc_for_pass > test_time then
      begin
        disc_for_pass:= test_time;
        segments_in  := test_segments_in;
        segments_out := test_segments_out;

        test_segments_in:= test_segments_in + 1;
        goto calc_segments_out;
      end  a better result;

    end  test_segments_out >= min_segs_per_block;

    disc_for_pass:= disc_for_pass * segsin;


    time:= (if test_shares = 1 then
               disc_for_pass + cpu_for_pass
            else
            (if disc_for_pass > cpu_for_pass then  disc_for_pass
             else  cpu_for_pass) * 1.10)
           + 2000.0 + time;

    test_in_segs (i):= segments_in;
    test_segs_out(i):= segments_out;
  end  for i;
\f




  segs_and_time:= time;

  if time < mintime then
  begin
  comment    return the hitherto best values;
    mintime:= time;
    passes:= test_passes;
    shares:= test_shares;
    for i:= 1 step 1 until test_passes do
    begin
      merge_power(i):= test_merge_power(i);
      in_segs    (i):= test_in_segs    (i);
      segs_out   (i):= test_segs_out   (i);
    end;
  end  a better result;
end  segs_and_time;

\f


  comment    before pass 1.
    strings1 contains the number of strings generated during
    pass 0, recs the real number of records, segsin the minimum size
    of the output file from the string generation;

    bytes_per_power:= maxlength + 106;
    <* 1 record + 8 bytes + zonedescriptor and 2 sharedescriptors *>

    first_pass:= if passes = 2 then  2 else  1;
    pass_step := if passes = 0 then  1 else  2;

    min_time:= great:= '10;
    for test_shares:= 1 step 1 until 2 do
    begin
      bytes_per_in_seg:= bytes_per_out_seg:= test_shares * 512;
      i:= minsegsperblock * bytes_per_in_seg + bytes_per_power;
      max_power    := (free_bytes - minsegsperblock
                       * bytes_per_out_seg) // i;
      last_maxpower:= (free_bytes - segs_per_out_block
                       * bytes_per_out_seg) // i;

      if test_shares = 2 then
      begin
        if      maxpower > messbufsforinp then
                maxpower:= messbufsforinp;
        if last_maxpower > messbufsforinp then
           last_maxpower:= messbufsforinp;
      end  doublebuffering;

      time_best_passes:= great;
      for test_passes:= first_pass step pass_step
                        until 20 do
      begin
        if find_powers then
        begin
        comment  ok;
          time:= segs_and_time;
          if time < time_best_passes then
             time_best_passes:= time
          else
            goto change_shares;
        end  find_powers;

      end  for testpasses;

change_shares:
    end  for shares;


  if mintime >= great then  alarm(10, 20);
comment
  this situation, that the sort can not be done in 20 passes, after 
  the checks performed in checkparam, must never occur, and should be
  considered a program error;


comment -test-< write(out, <:<10>    mintime: :>, <<ddd ddd.dd>,
  mintime/1000);

end    select_merge_strategy;

\f


procedure  select_work_file(situation, infile);
value  situation; integer situation;
real array  infile;
comment

  the procedure creates the workfile needed in the situation:

  1.  before pass 0, the stringgeneration.
      the original inputfile and the final outputdisc is checked.
      passes = 0 at calltime signals that the workfile should be
      the final outputfile.
      if that is impossible passes is set to 1 .
      discstores is set to 1 or 2 depending on whether the input- 
      file and the workfile is placed on the same disc or not.

  2.  before pass 1, the first merging pass.
      the return value of passes specifies the possible numbers
      of merging passes:
        0:  any number is allowed (1, 2, 3, ... )
        1:  only odd numbers      (1, 3, 5, ... )
        2:  only even numbers     (2, 4, 6, ... )

      discstores as for situation 1.
;
begin
  boolean  small_input_disc;

  integer  best_bsno, best_segments, best_weight, bsno, entries,
           free_segs_on_input_disc,
           i, input_bsno, max_loss_per_block, output_bsno,
           safe_segments, segments, segs_on_input_disc, 
           slice_length, weight;

  integer array  ia(1:20), tail(1:10);
  integer array  field headpart;

  long    array  bestbsname, bsname(1:2);

  real    array field  areaname, discname;

  zone  z(128, 1, stderror);
\f

 
boolean procedure claim
      (keyno,bsno,bsname,entries,segm,slicelength);
value keyno, bsno;
integer keyno,bsno,entries,segm,slicelength;
long array bsname;
begin
own boolean init;
own integer bsdevices,firstbs;
integer i;
real array ownname(1:2);
long array field name;
integer array core(1:18);
  if -,init then
  begin
    init:=true;
    system(5,92,core);
    bsdevices:=(core(3)-core(1))//2;
    firstbs:=core(1);
    system(6,i,ownname);
  end;
  if bsno<0 or bsno>=bsdevices 
  or keyno<>0 and keyno<>2 and keyno<>3 then
  begin 
    claim:=false;
    goto exitclaim
  end;
  claim:=true;
  begin integer array nametable(1:bsdevices);
    name:=18;
    system(5,firstbs,nametable);
    system(5,nametable(bsno+1)-36,core);
    if core(10) = 0 then  goto exitclaim;
    bsname(1):=core.name(1); bsname(2):=core.name(2);
    slicelength:=core(15);
comment    lookbs(ownname,bsname,core);
    entries:=2;
    segm:=c2size*2;
  end;
  if false then
  begin
exitclaim:
  entries:=segm:=slicelength:=0;
  bsname(1):=bsname(2):=0;
  end;
end claim;
\f


comment     lookup the input file;
  areaname:= discname:= 2;
  getzone6(z, ia);
  for i:= 1 step 1 until 2 do   ia.areaname(i):= infile(i);
  setzone6(z, ia);
  i:= monitor(42, z, 0, tail); <* lookup entry *>
  if i <> 0 then  alarm(4, i);

  if situation = 1 then
  begin
    segsin:= tail(1);
    if segsin < 0 then  alarm(8, segsin); <* no area *>
    content:= tail(9) shift(-12);
    if content <> 20 <* bs system *> and content <> 21 <*sq system*> then  content:= 0;

    if content = 21 then
    begin
      open(z, 4, infile, 0);
      invar(z);
      headpart:= 0;
      headpart:= z.headpart(3);
      param(1):= z.headpart(10) extract 12;
      headpart:= z.headpart(1);
      i:= z.headpart(3);
      if i < noofrecs then alarm(16, noofrecs);
      if noofrecs <= 0 then
      noofrecs:= i;
    end;

    safe_segments:= 2 * segsin; <* the safe workfile size *>
  end  situation 1
  else

  <* situation = 2 *>
  begin
  comment    calculate the safe size of the workfiles;
    i:= bytesperoutblock // 2;
    max_loss_per_block:=
      if fixedlength then  bytesperoutblock mod maxlength
      else
      ((if maxlength > i then  i else  maxlength) - 2);
    safe_segments:=
      round (segsin / (bytesperoutblock - max_loss_per_block)
             * bytesperoutblock)
      + 1 + segsperoutblock;
  end  situation = 2;
\f


comment
  comment now find the best disc for the workfile.
  the selection is based upon the following priorities:
  1: the final outputdisc if necessary or wanted.
  2: a disc with safe_segments free segments.
  3: the disc with most free segments.
  4: the disc with the greatest slicelength.
  5: a disc giving discstores = 2.
  6: the final outputdisc.
  7: the disc with the highest bsno.
;


  bsno:= best_weight:= input_bsno:= output_bsno:= -1;

  for bsno:= bsno + 1 
  while claim(0, bsno, bsname, entries, segments, slicelength) do
  if slicelength > 0 <* kit mounted *> then
  begin

    if bsno = 0 then
    begin
    comment    check the number of entries in main catalog;
      i:= (if situation = 1 then  param(2) else  1) + entries;
      if i < 2 then  alarm(13, i - 2);
    end  bsno = 0;


    weight:= if slicelength >= 80 then  16 else  slicelength//5;

  comment    check inputdisc and final outputdisc;

    if real bsname(1) = tail.discname(1) and
       real bsname(2) = tail.discname(2) then
    begin
    comment    this is the disc of the input file;
      input_bsno:= bsno;
      segs_on_input_disc:=
        (tail(1) + slicelength - 1)//slicelength*slicelength + segments;
      small_input_disc:= 
        segs_on_input_disc//2//slicelength*slicelength < safe_segments;

      free_segs_on_input_disc:= segments;
      segments:=
        (segs_on_input_disc - segsin)//slicelength*slicelength;
      <* segments = max unused segments on input disc *>
    end  inputdisc
    else
      weight:= weight + 2;


  comment    include segments in the weight;
    weight:= (if segments >= safe_segments then  8000000
              else
                 segments * 20)  +  weight;
\f


    if real bsname(1) = names(5) and
       real bsname(2) = names(6) then
    begin
    comment    this is the disc of the final outputfile;
      output_bsno:= bsno;
      weight:= weight + 1; <* after all the file shall end there *>

      if situation = 1 then
      begin
      comment    check that there is room;
        if input_bsno <> output_bsno or
           param(2) = 0 <* the inputfile is not removed *> then
        begin
        comment    there must be room now;
          if segments < segsin then   alarm(14, segsin);

          if passes = 0 <* sort without merge wanted *> then
             weight:= 8100000;
        end  room must be there now
        else
        <* input_bsno = output_bsno and param(2) <> 0 *>
        begin
          if passes = 0 and segments >= safe_segments <* safe *> then
             weight:= 8100000  <* sort without merge possible *>
          else
             passes:= 1;
        end  perhaps room on outputdisc;
      end  situation = 1
      else
      <* situation = 2 *>
      if input_bsno <> output_bsno <* it must be selected *> then
         weight:= 8100000;
    end  disc for final output;

    if  best_weight <= weight then
    begin
       best_weight:=  weight;
       best_bsno  :=  bsno;
       best_segments:= segments;
       for i:= 1 step 1 until 2 do  best_bsname(i):= bsname(i);
    end  better or equal;
  end  for bsno;
\f


comment    now the best disc has been selected;

comment -test-< write(out, <:<10>test 1, inpbs, outbs, bestbs, bestw, :>,
  <:bests, safe, soninp, sin::>, input_bsno, output_bsno, best_bsno, best_weight,
  bestsegments, safe_segments, segs_on_input_disc, segsin);


  if output_bsno = -1 then
  begin
  comment    check that special outputdisc is not wanted;
    if names(5) <> real<::> then  alarm(14, -1); <* does not exist *>
  end;

  if best_segments < segsin then  alarm(13, segsin);

  discstores:= if input_bsno = best_bsno then  1 else  2;

  if situation = 1 then
  begin
    best_segments:= segsin; <* a reasonable filesize *>
  end
  else
  <* situation = 2 *>
  begin
    if discstores = 1 then
    begin
      passes:= 0; <* any number of merging passes *>

      best_segments:= free_segs_on_input_disc; <* the free segments *>

      if small_input_disc or best_segments < safe_segments then
      begin
      comment    cut down the input file to a more safe size;
        tail(1):= best_segments:=
          if small_input_disc then  segsin else  safe_segments;


        i:= monitor(44, z, 0, tail);
        if i <> 0 then  alarm(5, i);
      end  little room or biased distribution;
    end  discstores = 1
    else
    <* discstores = 2 *>
    begin
      passes:=
             if output_bsno = -1 then
             <* passes is used to select the safest disc for final out *>
             (if segs_on_input_disc >= safe_segments and
                 best_segments      >= safe_segments then  0
              else
              if segs_on_inputdisc < bestsegments then  1 else  2)

             else
             <* special outputdisc *>
             if best_bsno = output_bsno then  1 else  2;
    end  discstores = 2;
  end  situation = 2;
\f


comment    now, at last, create the workfile;

  tail(1):= if best_segments > safe_segments then  safe_segments
            else  best_segments;
  for i:= 1 step 1 until 2 do
  begin
    ia.areaname(i):= real<::>;
    tail.discname(i):= real best_bsname(i);
  end;
  tail.discname(1):=names(5);tail.discname(2):=names(6);
  setzone6(z, ia);
  i:= monitor(40, z, 0, tail); <* create entry *>
  if i <> 0 then  alarm(3, i);
  getzone6(z, ia);
  for i:= 1 step 1 until 2 do
    sortfiles(2 * situation - 2 + i):= ia.areaname(i);
end  select_work_file;
\f


comment
  the sortfiles are initialized with empty names, because they are
  removed in case of alarms, see procedure alarm;

  for segsin:= 1 step 1 until 4 do  sortfiles(segsin):= real<::>;

comment
  normalize the names in paramenter names;
  for i:= 1 step 2 until 5 do
    if names(i) extract 8 = 0 then names(i+1):= real <::>;
  selectworkfile(1, names); <*set content, param(1), and noofrecs*>


comment    check the parameters;

  segsperinblock:= param(1);
  if segsperinblock < 1 or segsperinblock > 40 then  alarm(1, 1);

comment    clear input;
  if param(2) <> 0 and param(2) <> 1 then  alarm(1, 2);

  segsperoutblock:= if param(3) = 0 then segsperinblock else param(3);
  if segsperoutblock < 1 or segsperoutblock > 40 then  alarm(1, 3);

  bytes_perinblock := segsperinblock  * 512;
  bytes_peroutblock:= segsperoutblock * 512;

  i:= param(4);
  fixedlength:= i = 1;
  if i < 0 or i > 3 then  alarm(1, 4);

  maxlength:= param(5);
  if maxlength < 2 or
     maxlength > bytes_perinblock or
     maxlength > bytes_peroutblock or maxlength mod 2 <> 0 then
    alarm(1, 5);

  min_segs_per_block:= (maxlength + 510)//512;
  maxlength_plus_four:= maxlength + 4;
comment    these two values are often used in the planning;

  noofkeys:= param(6);
  if noofkeys < 1 or noofkeys > maxlength or noofkeys > 169 then
    alarm(1, 6);

begin
comment  block for check of keydescr, coresize and messagebuffers;
  integer  i, abstype, neededcorebytes, position;
  real array  rarr(1:2);


comment
  check the contents of integer array  keydescr;

  maxkeyposition:= 0;
  for i:= 1*2+1 step 2 until noofkeys*2+1 do
  begin
    abstype:= abs keydescr(i);
    if abstype = 5 <* absbyte *> then  abstype:= 1;
    position:= keydescr(i+1);
    if position < abstype or
       position > maxlength or
       position mod 2 <> 0 and abstype <> 1 or
       abstype < 1 or abstype > 4 then  alarm(2, i//2);
    if position > maxkeyposition then
      maxkeyposition:= (position + 1)//2*2;
  end  checkkeydescr;
  if fixedlength then  maxkeyposition:= 2;
comment    see declaration of array shortrec in block for pass 0;
\f


comment
  check the available amount of core;

  system(2, freebytes, rarr);

  neededcorebytes:= 6650 <* 350 bytes below the 7000 bytes *>
                    + bytesperinblock + bytesperoutblock
                    + 4*maxlength + 24*noofkeys;

  i:= free_bytes - needed_core_bytes;
  if i < 0 then  alarm(12, i);

comment
  subtract from the value of freebytes:
    1:  room for about 10 program segments + up to 12 segments extra.
    2:  room for 3 zone-descriptors, and 5 share-descriptors.
    3:  room for local variables.
    4:  room for keycode and 1 record in sort-zone;

  freebytes:= freebytes
    + (-6650 + 510 + 2*106)
    - maxlength
    - 24*noofkeys
    - ( if i > 3*12*512 then  12*512 else  i//3);


comment
  as i >= 0 freebytes will now satisfy the relation:
     freebytes >= 510 + 2*106 + 3*maxlength
                  + 512*(segsperinblock+segsperoutblock).
  this is a very important fact since the remaining algorithm of
  the program will ensure that the sorting can be done if 
  freebytes is not less than any of the following two expressions:

  1. string generation:
     512*(segs_per_in_block + min_segs_per_block)
       + 2*(maxlength + 4) + max_keyposition.
  2. merging passes:
     512*3*min_segs_per_block + 2*(maxlength + 106).
  where min_segs_per_block = (maxlength + 510)//512.

  find out the number of free message buffers from the job process;

  i:= system(6, 0, rarr);
  system(5, i+26, rarr);
  messbufsforinp:= rarr(1) shift (-36) extract 12 - 2;

comment
  the buffer claim is byte 26 of the job process description.

  the output zone requires up to 2 message buffers during a block change,
  one of these can also be utilized for write(out,...;

end  local block;

\f



comment
  now the parameters and the available core storage have been checked,
  and various global variables have been initialized;

comment  -test-< write(out, <:<10>test 2, freebytes, messbufsforinp:  :>, 
  freebytes, messbufsforinp);

comment test of procedure strategy, mintime is printed at the end of
  procedure strategy *test str.*
  write(out, <:<10>test 10 <10>:>) *test str.*

  for freebytes:= 80000, 40000, 20000, 
    7000 + 512*(segsperinblock + segsperoutblock) + 4*maxlength - 300,
    freebytes - 12*512 - maxlength - 400 do
  begin
    for segsin:= 8, 30, 125, 500, 2000, 8000 do
    begin
      for discstores:= 1, 2 do
      begin
        for outbytes:= 0 step 1 until discstores*2 - 2 do
        begin
          write(out, <:<10>freebytes, segsin, discstores, passes: :>,
          << dddd>, freebytes, segsin, discstores, outbytes) *test str.*
          noofrecs:= segsin * 512.0 / maxlength *test str.*

          for strings1:= 1, 10, 100, 1000 do
          begin
            passes:= outbytes *test str.*
            select_merge_strategy *test str.*
            write(out, <:      shares, strings1: :>, << dddd>,
            shares, strings1, <:<10>    segs:>) *test str.*

            for pass:= 1 step 1 until passes do
              write(out, << ddd>, segsout(pass)) *test str.*
            write(out, <:<10>    insegs  :>) *test str.*
            for pass:= 1 step 1 until passes do
              write(out, << ddd>, insegs(pass)) *test str.*
            write(out, <:<10>    m.p.    :>) *test str.*
            for pass:= 1 step 1 until passes do
              write(out, << ddd>, mergepower(pass)) *test str.*
          end
        end
      end
    end
  end;
\f



comment
  find out whether the sort can be done without merging passes.
  passes = 0 signals to the procedure select_work_file, that
  this is the case.
  if passes = 0 upon the return it is possible to do without merge;

  passes:= if noofrecs < 0 or
              noofrecs >
             (freebytes - maxkeyposition 
             - bytes_per_inblock - bytes_per_outblock)
             // maxlength_plus_four
           then  1 else  0;


comment  -test-< write(out, <:<10>test 3 :>, discstores, passes,
                 segsin);

  shares:= 1;

  if passes = 0 then
  begin
  comment    sort without merge;
    segsoutzero:= segsperoutblock;
    recs:= noofrecs; <* records in sortzone *>
  end  no merging
  else
  begin
  comment
    select a reasonable blocklength and number of shares for the
    string generating pass (pass 0).
    this is done in a quite intuitive manner, as a flat
    optimum is assumed;

    segsoutzero:=
      (free_bytes - bytes_per_inblock - 3*maxlength_plus_four)//(3*512);

  comment
    as a start take a third of the available core minus room for
    inputblock, 2 records in sortzone and maxkeyposition.
    this ensures a minimum stringlength of 2 records which in turn
    ensures that the string chaining records (6 bytes each) will
    not take up as much room as the  data records;
\f


    if messbufs_for_inp > 0 then
    begin
    comment    doublebuffering is possible;
      i:= segsoutzero // segsperinblock;
      if i >= 1+2*3 or ( i >= 1+2*1 and discstores = 2) then
      begin
      comment    choose doublebuffering;
        shares:= 2;
        segsoutzero:= (segsoutzero - segsperinblock) // shares;
      end  enough core for doublebuffering;
    end    enough messagebuffers for doublebuffering;

    i:= 4 * segsperinblock;
    if segsoutzero > i then  segsoutzero:= i;
    if segsoutzero < minsegsperblock then
       segsoutzero:= minsegsperblock;

  comment    calculate the number of records in sortzone;
    recs:= (freebytes - maxkeyposition
            - (segsperinblock + segsoutzero) * 512 * shares)
           // maxlength_plus_four;

    if noofrecs >= 0 and recs > noofrecs then
       recs:= noofrecs;

  end  select segsoutzero and shares;


comment -test-< write(out, <:<10>test 4, shares, segsoutzero, recs::>,
                                         shares, segsoutzero, recs);
\f



  pass:= 0;

  begin
  comment
    block for pass 0, string generation.
    the algorithm used here does very much look like the correspon-
    ding algorithm in the procedure tapesortadp.
    in order to speed up the code a bit, most quantities used in
    the inner loops are local;

    boolean  fixedlength;
    
    integer  i, active, dead, reclength, recsin, minlength,
        actual_maxlength, out_block_size, trap_situation;

    real  endfile;

    integer field  ifld, length, recordnumber;

    real field  endmark;

    real array  shortrec(1:(maxkeyposition + 2)//4);

    long field  lfld;

    real array field  first_part, out_base;

    zone  zin(shares*segsperinblock*128, shares, docerror),

          zout(shares*segsout_zero*128, shares, errorinoutfile),

          zsort((recs+1)*maxlength_plus_four//4+3*(noofkeys+1)+6, 1, docerror),

          zcomp(3*noofkeys+6, 1, stderror);
\f


  comment    initialization of constants;

    fixedlength:= param(4) = 1;
    length:= 2;
    endmark:= if fixedlength then  4 else  8;
    endfile:= eof;
    recsin:= noofrecs;
    reclength:= maxlength;
    minlength:= keydescr(1*2+2);
    if recsin < 0 and minlength < 8 then  minlength:= 8;
  comment
    the minimum length of a variable length record is the position of the
    first keyfield or endoffilemark, if it is used;

    i:= 1;
    if content = 21 then
    opensq(zin, string names(increase(i)), 1 shift 18, 
           (if fixedlength then maxlength else 0) shift 12
            add (if param(4) = 0 then 0 else 1))
    else
    open(zin, 4, names, 1 shift 18);
    i:= 1;
    if passes = 0 and content = 21 then
    opensq(zout, string sortfiles(increase(i)), 0, 
           (if fixedlength then maxlength else 0) shift 12 add 2)
    else
    open(zout, 4, sortfiles, 0);

    if param(4) = 0 and content <> 21 then
    begin
    comment    checksum control wanted, set free zone parameter;
      integer array  ia(1:20);
      getzone6(zin, ia); 
      ia(11):= 1 shift 23;
      setzone6(zin, ia);
    end  invar with checksum;

    actual_maxlength:= if fixedlength then  maxlength else  minlength;
    out_block_size:= segs_out_zero * 512;

    outrec6(zout, out_block_size);

    out_base:=
    strings1:= outsegment:= outbytes:= recsout:= recs:=
    active:= dead:= 0;


    if recsin = 0 then  goto endoffile;
\f


  comment    initialize zsort and zcomp.
             an extra keyfield, recordnumber, is included for zsort in
             order to retain the ordering of synonyms.
             zcomp is used in calls of sortcomp to determine whether
             a record can participate in the current string or not.
             in this comparison it is needless and impossible to in-
             clude the recordnumber;

    i:= 2*noofkeys + 4;
    begin
      integer array  local_keydescr(3:i);
      local_keydescr(i-1):= 2;
      local_keydescr(i  ):= recordnumber:= maxlength + 2;
      for i:= i-2 step -1 until 3 do  local_keydescr(i):= keydescr(i);

      startsort6(zcomp, local_keydescr, noofkeys  , recordnumber);
      i:=
      startsort6(zsort, local_keydescr,
                 noofkeys + (if recordnumber < 2047 then  1 else  0),
                 recordnumber);
    end  initialize zsort and zcomp;


    for i:= i step -1 until 1 do
    begin
    comment
      initial filling of zsort;

      if recsin = 0 then  goto endoffile;

      if fixedlength then  inrec6(zin, reclength)
      else
      begin
        invar(zin);
        reclength:= zin.length;
        if reclength > actual_maxlength then
        begin
          actual_max_length:= reclength;
          if reclength > maxlength then  alarm(9, reclength);
        end  a greater record
        else
        if reclength < minlength then  alarm(9, reclength);
      end  variable length;

      if recsin > 0 then  recsin:= recsin - 1
      else
      if zin.endmark = endfile then  goto endoffile;
      recs:= recs + 1;

      newsort(zsort);  active:= active + 1;

      for lfld:= maxkeyposition step -4 until reclength + 2 do
        zsort.lfld:= 0;
    comment    set undefined keyfields to zero;
      tofrom(zsort, zin, reclength);
      zsort.recordnumber:= recs;
    end  initial filling of zsort;


comment    start the writing of the first string;
\f


    trap(trap_pass_0);


nextout:

    trap_situation:= 1; <* comparison in zsort *>

    outsort(zsort);  active:= active - 1;
comment test trap - sqrt(param(8)-2);


fromlifesort:
    recsout:= recsout + 1;

    if -,fixedlength then  reclength:= zsort.length;

    if out_base + reclength > out_block_size then
    begin
    comment    change the output block;

      if pass = passes then
      begin
        for ifld:= out_base + 2 step 2 until out_blocksize do
            zout.ifld:= 0;
        first_part:= 0;
      end  zero fill in last pass
      else
      begin
        first_part:= out_blocksize - out_base;
        tofrom(zout.out_base, zsort, first_part);
      end  not final output;

      outrec6(zout, out_blocksize);
      out_base:= reclength - first_part;
      tofrom(zout, zsort.firstpart, out_base);
    end  change output block
    else
    begin
      if reclength < 26 then
      begin
      comment    move with a for statement;
        for lfld:= reclength step -4 until 4 do
          zout.outbase.lfld:= zsort.lfld;
        if lfld = 2 then  zout.outbase.length:= zsort.length;
      end  short rec
      else
        tofrom(zout.outbase, zsort, reclength);
      outbase:= reclength + outbase;
    end  normal record change;
\f


    if recsin = 0 then  goto endoffile;

    if fixedlength then  inrec6(zin, reclength)
    else
    begin
      invar(zin);
      reclength:= zin.length;
      if reclength > actual_maxlength then
      begin
        actual_maxlength:= reclength;
        if reclength > maxlength then  alarm(9, reclength);
      end  a greater record
      else
      if reclength < minlength then  alarm(9, reclength);
    end  variable length;

    if recsin > 0 then  recsin:= recsin - 1
    else
    if zin.endmark = endfile then  goto endoffile;
    recs:= recs + 1;
\f



    if reclength >= maxkeyposition then
    begin
    comment    there are no keyfields outside the record;

      trap_situation:= 2; <* in sortcomp zin *>
comment test trap - sqrt(param(8)-3);

      if sortcomp(zcomp, zin, zsort) < 0 then
      begin
      comment
        the record just read cannot participate in the current string,
        because it should have preceded the last written;

        deadsort(zsort);  dead:= dead + 1;
      end
      else
      begin
      comment
        the record can be included in the current string;

        newsort(zsort);  active:= active + 1;
      end  sortcomp;

      if reclength < 26 then
      begin
      comment    move with for statement;
        for lfld:= reclength step -4 until 4 do  zsort.lfld:= zin.lfld;
        if lfld = 2 then  zsort.length:= zin.length;
      end  short rec
      else
        tofrom(zsort, zin, reclength);

      zsort.recordnumber:= recs;
      if active > 0 then  goto nextout;
    end  no reset of undefined
    else
    begin
    comment
      the input record does not contain all keyfields, the undefined
      keyfields are set to zero before any comparison;

      for lfld:= maxkeyposition step -4 until reclength + 2 do
        shortrec.lfld:= 0;
      tofrom(shortrec, zin, reclength);

      trap_situation:= 3; <* in sortcomp shortrec *>
comment test trap - sqrt(param(8)-4);

      if sortcomp(zcomp, shortrec, zsort) < 0 then
      begin
      comment    see the comments above;
        deadsort(zsort);  dead:= dead + 1;
      end
      else
      begin
        newsort(zsort);  active:= active + 1;
      end;

      tofrom(zsort, shortrec, maxkeyposition);
      zsort.recordnumber:= recs;
      if active > 0 then  goto nextout;
    end  reset undefined;
\f


  comment
    only dead records are now left in the sortzone.
    terminate the current string, activate the dead records, and
    continue;

    strings1:= strings1 + 1;
    endoutstring(zout, out_base, out_block_size);

    trap_situation:= 1; <* comparison in zsort *>

    lifesort(zsort);  active:= dead - 1;  dead:= 0;
    goto fromlifesort;


trap_pass_0:
    if trap_situation = 1 then  print_zsort(zsort)
    else
    begin
    <* error in sortcomp *>
      print_rec(zsort.recordnumber, zsort);
      if trap_situation = 2 then  print_rec(recs, zin)
      else                        print_rec(recs, shortrec);
    end  in sortcomp;

    alarm(15, 0);


endoffile:
    recsin:= 0;
  comment
    the remaining active records are written to the current string.
    recsin = 0 makes the program return to endoffile without at-
    tempting further input;

    if active > 0 then  goto nextout;


    strings1:= strings1 + 1;

    if dead > 0 then
    begin
    comment
      terminate the current string, activate the dead records, and
      write the last string;

      endoutstring(zout, out_base, out_block_size);

      lifesort(zsort);  active:= dead - 1;  dead:= 0;
      goto fromlifesort;
    end  remaining dead;


    changerec6(zout, out_base);

    if param(2) = 1 then
    begin
    comment    remove the input file;
      i:= monitor(48, zin, 0, insegs);
      if i <> 0 then  alarm(7, i);
    end  clearinput
    else
      close(zin, true);

    if pass = passes then
      endoffilerec(zout);
  comment    endoffilerec jumps to returnfromdiscsort;


  comment    find the length of the file generated;
    getposition(zout, 0, segsin);
    segsin:= (out_base - 1)//512 + 1 + segsin;

    setposition(zout, 0, 0); <* forces the last block out *>

    if actual_maxlength < max_keyposition then
       actual_maxlength:= max_keyposition;
    maxlength          := actual_maxlength;
    maxlength_plus_four:= actual_maxlength + 4;


comment -test-< write(out, <:<10>test 5 , strings1, segsin, recs: :>,
  strings1, segsin, recs);
  end  string generation;

\f



comment
  now sorted strings have been output to the file, the name of which is
  stored in sortfiles(1:2);



  select_work_file(2, sortfiles);

comment
  a new workfile has been created. its name is stored in sortfiles
  (3:4).
  the number of disc stores available for the merge is specified by the
  value of the integer discstores, and the value of passes specifies the
  the possible numbers of passes;

comment -test-< write(out, <:<10>test 6 , discstores, passes: :>,
  discstores, passes);


  select_merge_strategy;

comment -test-< write(out, <:<10>test 7 , passes, shares: :>,
  passes, shares);

comment -test-< for pass:= 1 step 1 until passes do
  write(out, <:<10>test 8, s.in, s.out, m.p.: :>, insegs(pass), segsout(pass),
  mergepower(pass));

comment
  the value of passes defines the number of remaining passes.
  insegs, segsout(1:passes) contains the blocklengths of all passes,
  and mergepower(1:passes) contains the mergepowers.

  the value of shares specifies the number of shares to be used for
  input/output;


\f


  pass:= 1;

next_merging_pass:

  begin
  comment
    block for one merging pass;

    boolean  fixedlength;

    integer  i, reclength, instring, active, insegment, inbytes,
      nextrecsin, in_block_size, out_block_size;

    integer field  ifld, length, stringno;

    integer array  recsin, save_in_base(1:mergepower(pass));

    long field  lfld;

    real array field  first_part, in_base, out_base;

    zone array
        z(mergepower(pass), shares*in_segs(pass)*128, shares,
            docerror);

    zone
        zout(shares*segsout(pass)*128, shares, errorinoutfile),

        zmerge((mergepower(pass)+1)*maxlength_plus_four//4+3*(noofkeys+1)+6,
                1, docerror);


procedure  end_of_in_block(z, rec);
zone  z; real  array  rec;
comment

  reads the next record from z, taking the first part from the
  current block and the second part from the next;
begin
  
  first_part:= in_blocksize - in_base;
  tofrom(rec, z.in_base, first_part);
  in_base:= inrec6(z, 0);
  inrec6(z, in_base);
  if reclength = 1 000 000 then  reclength:= z.length;
  in_base:= reclength - first_part;
  tofrom(rec.first_part, z, in_base);
end  end_of_in_block;


  comment
    initialize local constants;

    fixedlength:= param(4) = 1;
    reclength:= maxlength;
    length:= 2;

  comment
    open all the input/output zones, and initialize the merge zone;
\f


    for instring:= 1 step 1 until mergepower(pass) do
    begin
      i:= if pass extract 1 = 1 then  1 else  3;
      open(z(instring), 4, string sortfiles(increase(i)), 1 shift 18);
    end  open instrings;

    i:= if pass extract 1 = 1 then  3 else  1;
    if pass = passes and content = 21 then
    opensq(zout, string sortfiles(increase(i)), 0,
           (if fixedlength then maxlength else 0) shift 12 add 2)
    else
    open(zout, 4, string sortfiles(increase(i)), 0);
    in_block_size := in_segs (pass) * 512;
    out_block_size:= (if pass = passes then  segs_per_out_block
                     else  segs_out(pass)) * 512;
    outrec6(zout, out_block_size);
    out_base:= 0;

    insegment:= outsegment;
    inbytes:= outbytes;
    nextrecsin:= recsout;

  comment
    these variables defines the position and length of the first input
    string for the merge, it is identical to the last created output
    string;

    outsegment:= outbytes:= recsout:= 0;

comment -test-< write(out, <:<10>test 20 , start pass: :>, pass);


    if nextrecsin = 0 then  goto terminatepass;
  comment    only relevant for zero records to sort;

  comment    initialize zmerge, stringno is included as the keyfield
             of the lowest priority in order to retain the ordering of
             synonyms.
             the sorting on the stringnumber is in decreasing order
             in passes with odd numbers because the strings here are
             read in reverse order;

    i:= 2*noofkeys + 4;
    begin
      integer array  local_keydescr(3:i);
      local_keydescr(i-1):= if pass extract 1 = 1 then  -2 else  2;
      local_keydescr(i  ):= stringno:= maxlength + 2;
      for i:= i-2 step -1 until 3 do  local_keydescr(i):= keydescr(i);

      startsort6(zmerge, local_keydescr,
                 noofkeys + (if stringno < 2047 then  1 else  0),
                 stringno);
    end  initialize zmerge;


    active:= 0;
\f


    trap(trap_pass_n);

    if false then
    begin
trap_pass_n:
      if active >= 2 then  print_zsort(zmerge);
      alarm(15, pass);
    end  trap;


fillzmerge:

    for instring:= 1, instring + 1 while instring <= mergepower(pass)
                                         and insegment >= 0 do
    begin
    comment
      position the zone corresponding to instring in front of the next
      string, read the string chaining record, and the first real record.
      the first record is inserted in zmerge;

      setposition(z(instring), 0, insegment);
      in_base:= in_bytes;
      i:= inrec6(z(instring), 0);
      inrec6(z(instring), i);

comment -test-< write(out, <:<10>test 21 , instring, insegment, :>,
<:inbytes, nextrecsin: :>, instring, insegment, inbytes, nextrecsin);


      recsin(instring):= nextrecsin - 1;
    comment
      recsin holds a counter of records for each instring;

      if insegment = 0 and inbytes = 0 then  insegment:= -1
      else
      begin
      comment    read the string chaining record;
        ifld:= 0;
        for i:= 1 step 1 until 3 do
        begin
          if in_base >= in_blocksize then
          begin
            in_base:= inrec6(z(instring), 0);
            inrec6(z(instring), in_base);
            in_base:= 2;
          end  blockchange
          else
            in_base:= in_base + 2;
          nextrecsin:= z(instring).in_base.ifld;
          case i of
          begin
            insegment:= nextrecsin;
            inbytes  := nextrecsin;
            <* nextrecsin is ok  *>
          end  case i;
        end  for i;
      end  chain to next instring;
\f


      newsort(zmerge);  active:= active + 1;

      if -,fixedlength then
        reclength:=
          if in_base < in_block_size then
             z(instring).in_base.length else  1 000 000;

      if in_base + reclength > in_block_size then
        end_of_in_block(z(instring), zmerge)
      else
      begin
        tofrom(zmerge, z(instring).in_base, reclength);
        in_base:= reclength + in_base;
      end  normal record change;
      save_in_base(instring):= in_base;
      for ifld:= reclength + 2 step 2 until maxkeyposition do
        zmerge.ifld:= 0;
    comment    set undefined keyfields to zero;
      zmerge.stringno:= instring;

comment -test-< printkey(recsout, instring, zmerge);

    end  initial filling of zmerge;

\f


nextout:
    outsort(zmerge);
comment test trap - sqrt(param(8)-5);
    instring:= zmerge.stringno;

    recsout:= recsout + 1;

comment -test-< if recsin(instring) mod param(8) = 0 then
                printkey(recsout, instring, zmerge);

    if -,fixedlength then  reclength:= zmerge.length;

    if out_base + reclength > out_block_size then
    begin
    comment    change the output block;
      if pass = passes then
      begin
        for ifld:= out_base + 2 step 2 until out_blocksize do
            zout.ifld:= 0;
        first_part:= 0;
      end  zero fill in last pass
      else
      begin
        first_part:= out_blocksize - out_base;
        tofrom(zout.out_base, zmerge, first_part);
      end  intermediate pass;

      outrec6(zout, out_blocksize);
      out_base:= reclength - first_part;
      tofrom(zout, zmerge.first_part, out_base);
    end  change out block
    else
    begin
      if reclength < 26 then
      begin
      comment    move with for statement;
        for lfld:= reclength step -4 until 4 do
          zout.out_base.lfld:= zmerge.lfld;
        if lfld = 2 then  zout.out_base.length:= zmerge.length;
      end  short rec
      else
        tofrom(zout.out_base, zmerge, reclength);
      out_base:= reclength + out_base;
    end  normal record change;
\f


    if recsin(instring) = 0 then  goto endofstring;

    recsin(instring):= recsin(instring) - 1;

    newsort(zmerge);

    in_base:= save_in_base(instring);
    if -,fixedlength then
      reclength:=
        if in_base < in_block_size then
          z(instring).in_base.length else  1 000 000;

    if in_base + reclength > in_block_size then
      end_of_in_block(z(instring), zmerge)
    else
    begin
      tofrom(zmerge, z(instring).in_base, reclength);
      in_base:= reclength + in_base;
    end  normal record change;
    save_in_base(instring):= in_base;

    for ifld:= reclength + 2 step 2 until max_key_position do
      zmerge.ifld:= 0;
  comment    set undefined keyfields to zero;
    zmerge.stringno:= instring;

    goto nextout;


endofstring:
    active:= active - 1;
    if active > 0 then  goto nextout;

  comment
    now all strings have been emptied, and a new round should be 
    started if there are more strings left;

    if insegment >= 0 then
    begin
      endoutstring(zout, out_base, out_block_size);
      goto fillzmerge;
    end  take a new round;
\f



terminatepass:



    changerec6(zout, out_base);

    if pass = passes then
    begin
    comment    remove input file;
      i:= monitor(48, z(1), 0, recsin);
      if i <> 0 then  alarm(7, i);
    comment    end the sort by procedure endoffilerec,
               which jumps to the label return_from_discsort;
      endoffilerec(zout);
    end  it was the last pass;


    setposition(zout, 0, 0); 
 comment    setposition forces the last block out;


comment -test-< write(out, <:<10>test 9 , pass, segsin, recsout: :>,
  pass, segsin, recsout);


    pass:= pass + 1;
    goto next_merging_pass;
  end  block for one merging pass;





alarmcall:
  system(9, segsin, string sortfiles(1));
comment
  the alarm is called here in order to obtain a simple alarm address;


returnfromdiscsort:

;comment -test-< write(out, <:<10>test 10, blocksread: :>, blocksread);
end  discsort;

\f


  procedure readallparam;
  begin
      real array field rf;
        
    comment
            ********************************************************
            *                                                      *  
            * This procedure reads all the parameters to incsave.  *
            *                                                      *
            ********************************************************; 
    last:=true;
    list:=true;total:=false;std:=true;
    sys:=true;
   rf:=0;
    vksegm:=8;psegm:=8;
    for i:= readparam(input) while i <> 0 do
    begin
      if i = -1 then
      openout else
      if input(1) = long <:segm:> then
      begin
        i:=readparam(input);
        if i = 3 then vksegm:=input.rf(1) else paramerror(6);
      end  else
      if input(1) = long <:since:> then
      begin
        i:=readparam(input);
        if input(1) = long <:last:> then last:=true else
        if i = 3 then
        begin
          last:=false;
          date:=readdate;
        end
        else
        paramerror(1);
      end  else
      if input(1) = long <:total:> then
      begin
        i:=readparam(input);
        if input(1) = long <:yes:> then total:=true
        else if input(1) = long <:no:> then total:=false
        else paramerror(2);
      end  else
      if input(1) = long <:tape:> then
      begin
        sys:=false;
        i:=readparam(tapename);
      end  else
      if input(1) = long <:std:> then
      begin
        i:=readparam(input);
        if input(1) = long <:yes:> then std:= true
        else if input(1) = long <:no:> then std:=false
        else paramerror(3);
      end  else
      if input(1) = long <:list:> then
      begin
        i:=readparam(input);
        if input(1) = long <:yes:> then list:=true
        else if input(1) = long <:no:> then list := false
        else paramerror(4);
      end;
    end;
  end;

  integer procedure readparam(val);long array val;
  begin
    own integer q;

    integer ik;
    if q>=0 then 
    begin
      ik:= system(4,q,val);
      ik:= (if ik shift (-12) = 8 then 2 else 0)+
      ik shift(-2) extract 2;
      if q = 0 then
      begin
        long array a(1:2);
        if system(4,1,a)=6 shift 12 + 10 then ik:=-1;
      end;
      q:= if ik = 0 then -1 else q+1;
      readparam:=ik;
    end else readparam:=0;
  end readparam;
\f


  integer procedure readdate;
  begin
     real array field rf;
    long array ra(1:2);
    long d;
    integer dd,mo,aa,hh,mm,ss,a,feb;
    rf:=0;
    d:=0;
    a:=68;
    hh:=0;mm:=0;ss:=0;
    ra(1):=input.rf(1);
    if ra(1) > 99 or ra(1) < 79 then paramerror(5);
    aa:=ra(1); readparam(ra);
    if ra.rf(1) >12 or ra.rf(1) < 1 then paramerror(5);
    mo:=ra.rf(1); readparam(ra);
    if ra.rf(1) < 1 then paramerror(5);
    dd:=ra.rf(1); readparam(ra);
    if ra.rf(1) > 23 then paramerror(5);
    hh:=ra.rf(1);readparam(ra);
    if ra.rf(1) > 59 then paramerror(5);
    mm:=ra.rf(1);
    feb:= if aa // 4*4=a/4*4 then 29 else 28;
    if dd>(case mo of (31,feb,31,30,31,30,31,31,30,31,30,31)) 
       then paramerror(5);
    for i := i while a<aa do
    begin
      d:=d+(if a//4*4=a/4*4 then 366 else 365);
      a:=a+1;
    end;
    d:=d+dd-1;
    if aa//4*4=aa/4*4 and mo > 2 then d:=d+1;
    if mo > 1 then
    d:=d+(case mo-1 of (31,59,90,120,151,181,212,243,273,304,334,365));
    d:=d*24*60*60+(hh*60*60+mm*60+ss);
    readdate:=(d*320000) shift (-24) extract (24);
  end readdate;
\f


  procedure paramerror(errornum);
  integer errornum;
  begin
    comment **************************************************
            *                                                *
            * This procedure is used to write the errormessa-*
            * ges.When tis procedure is entered the error    *
            * is hard and the program is terminated.         *
            *                                                *
            **************************************************;
    case errornum of
    begin
      <*1*> write(out,<:<10>*** wrong since specification :>);
      <*2*> write(out,<:<10>*** wrong total specification :>);
      <*3*> write(out,<:<10>*** wrong standard specification :>);
      <*4*> write(out,<:<10>*** wrong list specificaption :>);
      <*5*> write(out,<:<10>*** wrong date specification :>);
      <*6*> write(out,<:<10>*** wrong segm specefication:>);
      <*7*> write(out,<:<10>*** wrong psegm specification:>);
    end;
    write(out,<:<10> insave  stopped ***** :>);
    goto halt;
  end;
\f


  procedure incrementdump;

  begin
   comment  **************************************************
            *                                                *
            * Declarations of global variabels.              *
            *                                                *
            **************************************************;

    integer  hashentries,pagenr,nooflisten,dumpensize,bittsize,
    restondumps,dkey,mtrsize,ntape,noofentries,noofsegm,antalsegm,
    notapen,mtsize,device,nenintemp,notapsegm,modekind,pfileno,
    stofentry,filno,entrystart,blockno,bitpattern,newstofentry,
    pblockno,pfno,pbno,takind,totalsegm,entryno,ntshift,tntshift,
    dumpsize,outres,pdate,segmno,blocksize,trecordsize,
    ptapenr,tapenr,labelno,i,ii,j,k,l,m,ik,jk,kk,today,
    noofrecs,result,explanation,noofeninaux,totalsegmno,tq1;
     real array sortname(1:6);
    long array dcname(1:2),mt1pool(1:2),mtpool(1:2),
    tname(1:2),dump1name(1:2),p2catname(1:2),pcatname(1:2),t2name(1:2),
    tempname(1:2),tempdoc(1:2),
     temp1name(1:2),
    entryname(1:2),xlabel(1:25);
    real array field raf;
    real array field discname;
    long array field name,mtname,taname,docname,dname,tadocname,lo;
    integer field lbase,ubase,mtdate,mtnr,permkey,talbase,taubase,
    mttotal,tasize,size,kind,wordno,key,dbase1,dbase2,tasegmno, 
    startofbit,catnr,shortclock,contents,ih,mtno,dumpkey,proaddr;


    integer array field startofbitt;
    long rx;
         real wdate,r,whour,lastdate,eof,maxhashsize;
    boolean found,tapeshift,endtape,tendtape,identical,
    ttest,t1test,missingclock,listmore,sysdump,int,ptapeshift,
    harderror,nomess1;
    integer array entrybase(1:2),tail(1:10),iarr(1:10),interval(1:8),
    param(1:7),keydescr(1:4,1:2),ttail(1:17);
    zone entry(128,1,stderror);
    zone newcat(128,1,stderror);
    zone cat(128,1,stderror);
    zone cat1(128,1,stderror);
    zone outfil(128,1,stderror);
    zone help(1,1,stderror);
    zone help1(1,1,stderror);
    zone mtrecord(128,1,stderror);
    zone mt1record(128,1,stderror);
\f


    procedure tapeproc(z,s,b);
    zone z;
    integer s,b;
    begin
      comment
              ***************************************************
              *                                                 *
              * This procedure is a blockprocedure used to test *
              * endtape.If endtape is reached the boolean end-  *
              * tape is set to true.                            *   
              *                                                 *
              ***************************************************;
      if s shift (-18) extract 1 = 0 then stderror(z,s,b);
      endtape:=true;
    end;
\f


    procedure ptapeproc(z,s,b);
    zone z;
    integer s, b;
    begin
      comment
              **************************************************
              *                                                *
              * This procedure is also used to test endtape.   *
              * It is necsacary to have two becaurse this      *
              * procedure is working with an ther tape.        *
              *                                                *  
              **************************************************;
      if s shift (-18) extract 1 = 0 then stderror(z,s,b);
      tendtape:=true;
    end;
\f


    procedure warning(warningno);
    integer warningno;
    begin
      case warningno of
      begin
        <*1*> 
        begin
          ii:=1;
          write(out,<:<10> *** area process can not be created :>,
                 entry.name,<: not saved.:>);
          nooflisten:=nooflisten+2;
          if ttest then
          begin
            write(out,<:<10> size =:>,entry.kind);
            write(out,<:<10>result of create= :>,i);
          end;
        end;

        <*2*> 
        begin
          ii:=1;
          write(out,<:<10> *** The base of tempcat not ok.:>);
        end;
        <*3*> 
        begin
          write(out,<:<10>:>);
          write(out,<:<10> *** No savelabel on tape.The label is written:>);
         nooflisten:=nooflisten+2;
        end;
        <*4*>
        begin
          write(out,<:<10> *** Wrong savelabel on :>);
          write(out,tapename);
           goto halt;
        end;
      end;

    end;
\f


    procedure test(testno);
    integer testno;
    begin
      comment **************************************************
              *                                                *
              * This procedure is used to test the system. It  *
              * can be removed if the system is funktioning    *
              *                                                *
              **************************************************;
      if ttest then
      begin
        case testno of
        begin
          write(out,<:<10>*** test 1:>);
          write(out,<:<10>*** test 2:>);
          write(out,<:<10>*** test 3:>);
          write(out,<:<10>*** test 4:>);
          write(out,<:<10>*** test 5:>);
          write(out,<:<10>*** test 6:>);
        end;
      end;
    end;
\f


    procedure error(errorno);
    integer errorno;
    begin
      comment **************************************************
              *                                                *
              * This procedure is used to write the errormessa-*
              * ges.When tis procedure is entered the error    *
              * is hard and the program is terminated.         *
              *                                                *
              **************************************************;
      savenotok:=true;
      case errorno of
      begin
        <*1*>;
        <*2*>;
        <*3*>;
        <*4*>write(out,<:<10>*** Savecat does not exist:>);
        <*5*>write(out,<:<10>*** No permanent ressources on :>,resname);
        <*6*>write(out,<:<10>*** Temperary mtpool not ok:>);

        <*7*> write(out,<:<10>*** Mtpool does not exist.:>);
        <*8*> write(out,<:<10>*** Creation of temporary savecat not ok:>);
        <*9*> write(out,<:<10>*** Savecat not renamed:>);
        <*10*> write(out,<:<10>*** Tempcat does not exist:>);
        <*11*> write(out,<:<10>*** Tempcat not ok :>);
        <*12*> write(out,<:<10>*** Renaming tempcat impossibel:>);
        <*13*> write(out,<:<10>*** creation of tem1cat not ok:>);
        <*14*> write(out,<:<10>*** creation of new tempcat not ok :>);
        <*15*> write(out,<:<10>*** creation of tem1cat not ok:>);
        <*16*> 
        begin
          write(out,<:<10>*** the catalog can not be sorted:>);
          write(out,<:  result of mdsortproc = :>,result);
          write(out,<: explanantion = :>,explanation);
        end;
      end;
      write(out,<:<10> insave  stopped ***** :>);
      goto halt;
    end;
\f


    procedure auxscan(idate);
    integer idate;
    begin
      comment
              ********************************************************
              *                                                      *
              * This procedure search all auxcat through to find     *
              * those entries which shall be saved.                  *
              *                                                      *
              ********************************************************;
      long t2date,idag;
      procedure bsareaproc(z,s,b);
      zone z;
      integer s,b;
      begin
        if s shift (-23) extract 1 = 0 then stderror(z,s,b);
        noofeninaux:=0;
        write(out,<:<10>*** intervention from auxcat :  :>);
            write(out,auxcat);
        int:=true;
      end;
      long array doc2name(1:2),en2name(1:2);
      long array field d2name;

      integer array iarr(1:20),ihelp(1:1),t2tail(1:10);
      long array field tdocname;
      integer field endate,hsize;
      boolean field slize;
      integer catalogs,ik,csize,coraddr;
      long array catalog(1:2),auxcat(1:2),auxdoc1(1:2);
      zone dumpcat(128,1,stderror),auxentry(128,1,bsareaproc);
      slize:=1;
      idag := extend 0 add idate;
      endate:=18;d2name:=18;
      hsize:=16;tdocname:=2;
      for i:=1 step 1 until 10 do tail(i):=0;
      system(5) move core area:(92,iarr);
      catalogs:= (iarr(3)-iarr(1))/2;
      begin
        long array auxdoc(1:catalogs,1:2);
        long array catname(1:catalogs,1:2);
        integer array catsize(1:catalogs,1:1);
        test(1);
        noofentries:=0;noofeninaux:=0;noofsegm:=0;
        int:=false;
        k:=iarr(1);
        for j:=1 step 1 until catalogs do
        begin
          system(5)move core area:(k,ihelp);
          k:=k+2;
          system(5,ihelp(1)-2,iarr);
          system(5,ihelp(1)-28,catalog);
          test(2);        open(entry,4, catalog,0);
          i:=monitor(76)look up head and tail:( entry,0,iarr);
          if ttest then write(out,<:<10> look up head and tail result=:>,i);
          close(entry,true);
          catname(j,1):=iarr.name(1);
          catname(j,2):=iarr.name(2);
          catsize(j,1):=iarr.hsize;
          auxdoc(j,1):=iarr.docname(1);
          auxdoc(j,2):=iarr.docname(2);
          if ttest then
          begin
            write(out,
            <:<10> catalog name =:>,iarr.name);
          end;
        end;
        open(dumpcat,4,tname,0);
        if monitor(42)lookupentry:(dumpcat,0,tail) <> 0 then
        begin
        tail(1):=100;
        tail(2):=1;tail(3):=0;tail(4):=0;tail(5):=0;
        i:=monitor(40)create entry:(dumpcat,0,tail);
        if i <> 0 then error(13);
        end;
        for j:=1 step 1 until catalogs do
        begin
          test(3);
          auxcat(1):=catname(j,1);
          auxcat(2):=catname(j,2);
          csize:=catsize(j,1);
           open(help,0,auxcat,0);
            close(help,false);
           if monitor(76) lookup head and tail :(help,0,iarr) = 0 then
          begin
          open(auxentry,4,auxcat,1 shift 23);
          noofeninaux:=0;
          csize:=csize-1;
          if int then goto intven;
          for ik := inrec6(auxentry,0) 
          while ik > 0 and csize >= 0 and -,int do 
          begin
            test(4);
            if ttest then
            write(out,<:<10> result of inrec6 =:>,ik);
            if int then goto intven;
            if ik = 2 then 
            begin
              inrec6(auxentry,2);csize:=csize-1;
            end else
            begin
              inrec6(auxentry,34);
              if auxentry.key <>-1 and auxentry.key extract 3 >2   then
              begin
                monitor(72)set catalog base:(zhelp,0,interval);
                if auxentry.kind < 0 then
                begin
                  if auxentry.kind <> 1 shift 23 + 4 then goto tsave else
                  begin
                    entryname(1):=auxentry.name(1);
                    entryname(2):=auxentry.name(2);
                    if entryname(1) =  auxentry.docname(1) and
                       entryname(2) = auxentry.docname(2) then goto tsave;
                    entrybase(1):=auxentry.lbase;
                    entrybase(2):=auxentry.ubase;
                    i:=monitor(72)set catalog base:(zhelp,0,entrybase);
                    if i <> 0 then goto nottosave;
                    open(help,0,auxentry.docname,0);
                    close(help,false);
                    ii:=monitor(76)lookup head and tail:(help,0,iarr);
                    if  ttest then
                    begin
                      write(out,<:<10> result of lookupheadandtail= :>,i);
                      write(out,<:<10> doc222name= :>,
                             iarr.docname);
                    end;
                    while iarr.kind < 0 and ii = 0 do
                    begin
                      if iarr.kind <> 1 shift 23 + 4 then goto tsave;
                      entrybase(1):=iarr.lbase;
                      entrybase(2):=iarr.ubase;
                      monitor(72)set catalog base:(zhelp,0,entrybase);
                      open(help,0,iarr.docname,0);
                      close(help,false);
                      ii:=monitor(76)look up head and tail:(help,0,iarr);
                      if ttest then write(out,<:name22= :>,
                       iarr.docname);
                    end;
                    if ii <> 0 then goto tsave;
                    if ii = 0 then
                    begin
                      doc2name(1):=iarr.docname(1);
                      doc2name(2):=iarr.docname(2);
                      en2name(1):=iarr.name(1);
                      en2name(2):=iarr.name(2);
                      if ttest then write(out,<:<10>docname = :>,
                       auxentry.docname);
                      if ttest then write(out,<:<10> doc2name= :>,
                       doc2name);
                      ii:=lookupaux(en2name,doc2name,t2tail);
                      if ii <> 0 and ttest 
                      then write(out,<:<10> result of lookupaux= :>,ii);
                      if ttest then write(out,<:<10>date =:>,t2tail(2));
                      t2date:= extend 0 add t2tail(2);
                      if -,(t2date >= idag) then goto nottosave;
                    end else goto nottosave;
                  end;
                end else
                t2date:= extend 0 add auxentry.endate ;
                if -,(t2date >= idag) then goto nottosave;
                test(5);
                antalsegm:=antalsegm+auxentry.size;
tsave:          
                monitor(72)set catalog base:(zhelp,0,interval);

                entrybase(1):=auxentry.lbase;
                entrybase(2):=auxentry.ubase;
                entryname(1):=auxentry.name(1);
                entryname(2):=auxentry.name(2);
                if entryname(1) = mtpool(1) and
                entryname(2) = mtpool(2) and
                entrybase(1) = interval(5) and
                entrybase(2) = interval(6) then goto nottosave;
                if entryname(1) = dcname(1) and
                entryname(2) = dcname(2) and
                entrybase(1) = interval(5) and
                entrybase(2) = interval(6) then goto nottosave;
                if entryname(1) = pcatname(1) and
                entryname(2) = pcatname(2) and
                entrybase(1) = interval(5) and
                entrybase(2) = interval(6) then goto nottosave;
                if t1test  and entryname(1) = long <:primo:> add 115 then 
                begin
                  write(out,<:<10>entry name =:>,
                   entryname);
                  write(out,<:<10> date of entry = :>,auxentry.endate);
                end;
                open(help,0, entryname,0);
                close(help,true);
                i:=monitor(72)set entry base:(zhelp,0,entrybase);
                if i <> 0 then goto nottosave;
                if ttest then
                begin
                  write(out,<:<10>entry name:>,
                   entryname);
                  write(out,<:<10>set entry base result =:>,i);
                end;
                i:=monitor(76)lookup head and tail:(help,0,iarr);
                if i <> 0 then goto nottosave;
                if  ttest then
                write(out,<:<10> lookup entry result = :>,i);
                monitor(72)set catalog base:(zhelp,0,interval);
                outrec6(dumpcat,34);
                tofrom(dumpcat,auxentry,34);
                if iarr.kind >= 0 then
                begin
                  dumpcat.docname(1):=iarr.docname(1);
                  dumpcat.docname(2):=iarr.docname(2);
                end else
                begin
                  dumpcat.docname(1):=auxdoc(j,1);
                  dumpcat.docname(2):=auxdoc(j,2);
                end;
                if ttest then
                begin
                      write(out,<:<10>docname=:>,
                   iarr.docname);
                end;
                noofeninaux:=noofeninaux+1;
nottosave:      
              end;
              if ttest and ik = 2 then
              write(out,<:<10>csize=:>,csize);
            end;
          end;
          if ttest then
          begin
            write(out,<:<10> catalog with the following name  :>);
            write(out, auxcat);
            write(out,<: is searched through.:>);
          end;
intven:   
          int:=false;
          noofentries:=noofentries+noofeninaux;
          close(auxentry,true);
          end;
        end;
      end;
      monitor(72)set catalog base:(zhelp,0,interval);
      monitor(42)look up entry:(dumpcat,0,tail);
      c2size:=tail(1);
      c2size:=c2size+10;
      close(dumpcat,true);
    end;
    long procedure dumplabel(ii ,typ);
    integer ii,typ;
    begin
      long spaces,stop;
      comment
              *********************************************************  
              *                                                       *
              * returns the i'the real of a savelabel                 *  
              *        1: dump                                        *
              *        2-3: tapename                                  *
              *        4: filno                                       *
              *        5: vers.                                       *
              *        6: date                                        *
              *        7: hour                                        *   
              *        8: segments                                    *
              *        9-10: dumplabelname                            *  
              *        11: emtty                                      *
              *        12-13: emtty                                   *
              *        14: <:nl:>                                     *    
              *        15: <:em:>                                     *
              * The dumplabel is a text which may be read by    *
              * edit.                                                 *
              *                                                       *
              *********************************************************;
      long procedure convintg(n);
      value n;
      integer n;
      comment
              ***********************************************************
              *                                                         *
              * Converts a non negative integer to a text portion *
              * with the layout <<zddddd>.                              *   
              *                                                         *
              ***********************************************************;
      convintg:=if n <10 then long <:00000:> add (n+48)
      else convintg (n//10) shift 8 add (n mod 10+48);
\f


      long procedure spacefill(text);
      value text;
      long text;
      begin
        comment spacefill will replace trailing nulls by spaces;
        integer i;
        if text = long <::> then text:=spaces
        else
        begin
          i:=-1;
          for i:=i+1 while text extract 8 = 0 do text := text shift (-8);
          for i:=i-1 while i>-1 do text:= text shift 8 add 32;
        end;
        spacefill:=text;
      end <* spacefill*>;


      spaces:= long <:     :> add 32;
      stop:= long <:<10>:>;
      dumplabel:= case ii of (
      spacefill(long <:dump:>),
      spacefill(tapename(1)),
      spacefill(tapename(2)),
      spacefill(convintg(filno) shift 24),
      spacefill( case typ of ( long <:vers.:>,
              long <:empty:>, long <:cont.:>)),
      convintg(wdate),
      spacefill(long <:   .:> add
         ( convintg(whour) extract 16) shift 24 ),
      if typ = 2 then spaces else
      spacefill( long <:s=0:> shift (-24) add vksegm shift 24),
      spacefill(tapename(1)),
      spacefill(tapename(2)),
      spacefill(spaces),
      spacefill(spaces),
      spacefill(spaces),
      stop,
      long <:<25>:> shift (-8));

    end dumplabel;
\f


    procedure writelabel(typ);integer typ;
    begin
      zone zlabel(25,1,eror);
      procedure eror(z,s,b);zone z; integer s,b;
      if s shift 5 >= 0 then stderror(z,s,b); <*ignore eot*>
      if sys then
      open(zlabel,modekind, t1tapename,0) else
      open(zlabel,modekind,tapename,0);


      setposition(zlabel,if typ = 2 then 2 else 1,0);
      systime(1,0,r);
      wdate:=systime(2,r,r);
      whour:=r/10000-0.3;
      outrec6(zlabel,100);
      if typ = 2 then filno:=2 else filno:=1;
      for i:=1 step 1 until 15 do zlabel.lo(i):=dumplabel(i,typ);
      for i:=16 step 1 until 25 do zlabel.lo(i):= long <::>;
      if typ = 2 then setposition(zlabel,-1,0); 
      if typ = 3 then
        zlabel.lo(25):=long <::> add entryno shift 24 add (segmno-1);
     if typ = 3 then
     begin
       for i:=1  step 1 until 25 do xlabel(i):=zlabel.lo(i);
     end;
     if list and typ = 1 then
     begin
       for i:=1  step 1 until  25 do xlabel(i):=zlabel.lo(i);
       write(out,<:<12>:>);
       write(out,"sp",60,<:page :>,pagenr);
       nooflisten:=3;
       pagenr:=pagenr+1;
       write(out,<:<10>savelabel: :>,  xlabel);
     end;
      close(zlabel,false);
    end;
\f


    procedure testlabel(update);
    boolean update;
    begin
      integer array ia(1:8);
      zone pttape(2*130,2,tapeproc);
       long array field lof;
       lof:=0;
          labelno:=1;
      open(pttape, modekind,  tapename,0);
       setposition(pttape,0,0);
      setposition(pttape,labelno,0);
      i:=0;
      i:=inrec6(pttape,i);
      if i <> 100 then 
      begin
        warning(3);
        if update then
        begin
          close(pttape,false);writelabel(1);
          goto la;
        end;
      end
      else inrec6(pttape,100);
      if pttape.lof(2) <> dumplabel(2,1) or pttape.lof(3) <> dumplabel(3,1) then
      begin
      tapename(1):=pttape.lof(2);
       tapename(2):=pttape.lof(3);
      write(out,<:<10>:>);
      warning(4);
      end;
      if update then
      begin
        setposition(pttape,labelno,0);
        systime(1,0,r);
        wdate:=systime(2,r,r);
        whour:= r/10000 - 0.3;
        outrec6(pttape,4*25);
        for i:= 1 step 1 until 15 do
         pttape.lof(i):= xlabel(i):=dumplabel(i,1);
        for i:= 16 step 1 until 25 do pttape.lof(i):= xlabel(i):=long <::>;
        if list then
        begin
          write(out,<:<10>:>);
          write(out,<:<12>:>,"sp",60,<:page :>,pagenr);
          write(out,<:<10>savelabel: :>, xlabel);
          nooflisten:=1;
          pagenr:=pagenr+1;
        end;
      end else
        begin
        psegm:=pttape(8) shift (-24) extract 8;
        psegm:=if psegm = 32 then 1 else psegm-48;
        end;

      close(pttape,false);
la:   
    end;
\f


    procedure fletcatalog;
    begin
      integer array ia(1:10);
      integer pentryno,pentry;
      comment
              *******************************************************
              *                                                     *
              * This procedure merged the two catalog tempcat and   *
              * tem1cat together.                                   *
              *                                                     *
              *******************************************************;
      zone dumpcat(128,1,stderror),dump(128,1,stderror),
           cat(128,1,stderror);
      integer l,antal,catsize;
      integer field ih;
      long array field lname;
      boolean more;
      long array field tadocname;
      integer array ttail(1:17);
      zone help1(1,1,stderror);
      procedure indump;
      begin
        integer kk;
        if pentry < pentryno then
        begin
          kk:=inrec6(dump,0);
          if kk = 0 then more:= false else
          inrec6(dump,34);
         while dump.key = - 1 and more do
         begin
           kk:=inrec6(dump,0);
           if kk = 0 then more := false else
           inrec6(dump,34);
         end;
         pentry:=pentry+1;
       if ttest then write(out,<:<10>indump called :>);
       end else more:=false;

      end;
      procedure outdump;
      begin
        if ttest then 
        begin
          write(out,<:<10>outdump called:>);
          write(out,<:<10> navn = :>, dump.name);
        end;
        notapen:=notapen+1;
        outrec6(cat,34);
        tofrom(cat,dump,34);
        indump;

      end;

      procedure outcat;
      begin
        i:=i+1;
        if t1test then
        begin
          write(out,<:<10> antal = :>,i);
          write(out,<:<10> navn1= :>, dumpcat.name);
        end;
        outrec6(cat,34);
        tofrom(cat,dumpcat,34);
        if i <= noofentries then inrec6(dumpcat,34);
      end;
      notapen:=0;
      lname:=6;more:=true;
      monitor(72)set catalog base:(zhelp,0,interval);
      open(dumpcat,4, tempname,0);
      open(dump,4, pcatname,0);
       monitor(42)lookupentry:(dump,0,tail);
       pentryno:=tail(10);
       pentry:=1;
      t2name(1):=0;
      t2name(2):=0;
      monitor(42)look up entry:(dumpcat,0,tail);
      catsize:=tail(1);
      k:=    monitor(42)look up entry:(dump,0,tail);
      if k <> 0 then error(10);
      catsize:=catsize+tail(1)+1;
      for l:=1 step 1 until 10 do tail(l):= 0;
      tail(1):=catsize;
      tadocname:=2;
      tail(2):=1;
      tail(3):=0;tail(4):=0;tail(5):=0;
           open(cat,4, p2catname,0);
      monitor(48)remove entry:(cat,0,ia);
      if monitor(40)create entry:(cat,0,tail) <> 0 then error(14);
      i:=monitor(50)permanent entry:(cat,3,tail);
      if i <> 0 then
      begin
        if ttest then write(out,<:<10>tempcat:>); 
        error(5);
      end;
      entrybase(1):=interval(5);entrybase(2):=interval(6);
      i:=monitor(74)set entry base:(cat,0,entrybase);
      if i<> 0 then
      begin
        if ttest then write(out,<:<10>set entry base tempcat:>);
        error(5);
      end;
      setposition(cat,0,0);
      if k <> 0 then goto nopcat;
      antal:=0;
      l:=0;
      setposition(dump,0,0);
      inrec6(dumpcat,34);inrec6(dump,34);
      i:=1;j:=0;
      while i <= noofentries  or more do
      begin
        j:=j+1;
        if  -, more and i <= noofentries then outcat else
        begin
          if more then
          begin
          while dump.key = -1 do 
          begin
           
          indump;
          if -,more then goto la1;
          end; 
          end;
           open(help1,0, dump.name,0);
          entrybase(1):=dump.lbase;entrybase(2):=dump.ubase;
          monitor(72) set catalog  base:(zhelp,0,entrybase);
          k:= monitor(76)look up head and tail:(help1,0,ttail) ;
          monitor(72)set catalog base:(zhelp,0,interval);
          if k <> 0 or
           dump.lbase <> ttail(2) or dump.ubase <> ttail(3) then
          begin
            if ttest then write(out,<:<10>name=:>,
                   dump.name);
          end;
          close(help1,false);
          if i > noofentries then outdump else
          begin
            if dumpcat.lname(1) < dump.lname(1) then outcat else
            begin
              if dumpcat.lname(1) = dump.lname(1) then 
              begin
                if dumpcat.lname(2) < dump.lname(2) then outcat else 
                begin
                  if dumpcat.lname(2) = dump.lname(2) then
                  begin
                    if dumpcat.ubase < dump.ubase then outcat else
                    begin
                      if dumpcat.ubase = dump.ubase then
                      begin
                        if dumpcat.lbase < dump.lbase then outcat else
                        begin
                          if dumpcat.lbase = dump.lbase then
                          begin
                            outcat;indump;
                          end else outdump;
                        end;
                      end else outdump;
                    end;
                  end else outdump;
                end; 

              end else outdump;
            end;
          end;

        end;
la1:

      end;
      while more and i>= noofentries do
          outdump;
      noofentries:=noofentries+notapen;
      if t1test then write(out,<:<10> no of entries = :>,noofentries);
      for i:= 1 step 1 until 15 do
      begin
      outrec6(cat,34);
      for ih:=2 step 2 until 34 do cat.ih:=-1;
      end;
      tadocname:=0;
      setposition(cat,0,0);
      close(cat,true);
      close(dump,true);
      i:=monitor(40)look_up_entry:(cat,0,tail);
      tail(1):=(noofentries+1)//15 +1;
      i:=monitor(44)change_entry:(cat,0,tail);
      if i <> 0 then error(11);
nopcat:
      close(dumpcat,true);close(dump,true);
    end;
\f


    procedure mount_med_ring(ring);
    boolean ring;
    begin
      integer array ia(1:12),m(1:8);
      zone z(128,1,stderror);
      for i:=1 step 1 until 8 do m(i):=0;
      m(5):=tapename(1) shift (-24) extract 24;
      m(6):=tapename(1) extract 24;
      m(7):=tapename(2) shift (-24) extract 24;
      m(8):=tapename(2) extract 24;
      open(z,0, tapename,0);
      if monitor(4)process desc:( z,0,ia) = 0 then
      begin
        m(1):=16 <*opmess*> shift 12;
        m(2):= long <:rin:> shift (-24) extract 24;
        m(3):= long <:g:> shift (-24) extract 24;
        m(4):= 32 shift 16;
        system(10)parrant message:(0,m);
      end;
sense:
      monitor (6)initialize process:( z,0,ia);
      getshare6(z,ia,1);
      ia(4):=0; 
      setshare6(z,ia,1);
      monitor (16)send message:( z,1,ia);
      if monitor(18)wait answer:(z,1,ia) <> 1 <*not normal*> then
      begin
        comment not mounted;
        ia(1):= (if device = 0 then 14 shift 12 else 
        32 shift 12 +1 shift 9) + 1 shift 0;
        ia(2):= long <:mou:> shift (-24) extract 24;
        ia(3):= long <:nt:> shift(-24) extract 24;
        ia(4):= device;
        for i:= 5 step 1 until 8 do ia(i):=m(i);
        system(10,0,ia);
        goto sense;
      end
      else
      if ring then
      begin
        if ia(1) shift (-15) extract 1 = 0 then
        begin
          close(z,false);
          open(z,4 shift 12 + 18,  tapename,0);
          ia(1):= 18<*ring*> shift 12 + 1 shift 0;
          ia(2):= long <:rin:> shift (-24) extract 24;
          ia(3):= long <:g:> shift (-24) extract 24;
          ia(4):=0;
          for i:=5 step 1 until 8 do ia(i):=m(i);
          system(10,0,ia);
          goto sense;
        end;
      end;
      close(z,false);
    end mount med ring;
\f


    procedure inittempcat(rname);
    long array rname;
    begin
      comment
              **********************************************************
              *                                                        *
              * This procedure is used to initialise tempcat and tem1- *
              * cat.                                                   *  
              *                                                        *
              **********************************************************;
      integer field a;
           open(cat,4, rname,0);
      i:=monitor(42)look up entry:(cat,0,iarr);
      if i <> 0 then 
      begin
        iarr(1):=10;
         iarr(2):=1;iarr(3):=0;iarr(4):=0;iarr(5):=0;
        monitor(40)create entry:(cat,0,iarr);
      end;
      for i:= 1 step 1 until iarr(1) do
      begin
        setposition(cat,0,i);
        outrec6(cat,512);
        for ik := 1 step 1 until 256 do
        begin
          a:=ik*2;
          cat.a:=-1;
        end;
      end;
      close(cat,true);
    end;
\f


    procedure initnewcat;
    begin
      comment
              *************************************************************
              *                                                           *
              * This procedure initialise the new dumpcat  so that every  *
              * word of it contains -1. This is only done if an reorgani- *
              * sation of dumpcat is nessacary.                           *  
              *                                                           *
              *************************************************************;
      integer field a;
      for i:= 0 step 1 until hashentries-1 do
      begin
        setposition(newcat,0,i);
        outrec6(newcat,512);
        for ik:=1 step 1 until 256 do
        begin
          a:=ik*2;
          newcat.a:=-1;
        end;
        a:=2;newcat.a:=0;
      end;
    end;
\f


    procedure reorg;
    begin
\f


      procedure computenewhash;
      begin
        integer array primtal(1:19);
        integer primi;
        primtal(1):=101;
        primtal(2):=167;
        primtal(3):=217;
        primtal(4):=373;
        primtal(5):=557;
        primtal(6):=787;
        primtal(7):=1103;
        primtal(8):=1657;
        primtal(9):=2459;
        primtal(10):=3671;
        primtal(11):=5449;
        primtal(12):=8039;
        primtal(13):=12073;
        primtal(14):=18013;
        primtal(15):=27091;
        primtal(16):=40111;
        primtal(17):=60811;
        primtal(18):=90203;
        primi:=1;
        while hashentries > primtal(primi) do primi:=primi+1;
        hashentries:=primtal(primi+1);
     end;
      integer array duname(1:10);
      integer field a;
      integer array field point;
      long array cname(1:2);
      integer oldhashentries;
      monitor(72)set catalogbase:(zhelp,0,interval);
      point:=0;
      write(out,<:<10> --- the dumpcat is reorganised:>);
      oldhashentries:=hashentries;
      computenewhash;
      for i:=1 step 1 until 10 do tail(i):=0;
      tail(1):=hashentries;
      tail(2):=1;
      tail(10):=dumpensize;tail(9):=11 shift 12;
      cname(1):=long <::>;cname(2):=long <::>;
           open(newcat,4, cname,0);
      if monitor(40)create entry:(newcat,0,tail) <> 0 then error(8);
      monitor(74)setentry base:(newcat,0,interval);
           open(cat,4, dump1name,0);
      initnewcat;
      for i:=0 step 1 until oldhashentries-1 do
      begin
        setposition(cat,0,i);
        swoprec6(cat,2);
        rhashentry;
        while cat.catnr=-1 do rhashentry;
        dkey:=hashkey(cat.dname);
        setposition(newcat,0,dkey);
        swoprec6(newcat,2);
        if newcat.catnr = -1 then newcat.catnr:=0;
        newcat.catnr:=newcat.catnr+1;
        swoprec6(newcat,dumpensize);
        k:=1;
        while newcat.catnr <> -1 do swoprec6(newcat,dumpensize);
       tofrom(newcat,cat,dumpensize);
        newcat.catnr:=dkey;
      end;
      for i:=1 step 1 until 10 do duname(i):=0;
      for i:=1 step 1 until 4 do duname(i):=dump1name.point(i);
      close(cat,true);
      monitor(48)remove entry:(cat,0,tail);
      close(newcat,true);
      if monitor(46)rename_entry:( newcat,0,duname) <> 0 then error(9);
    end;

\f


    procedure hashtsize;
    begin
      comment
               ********************************************************
              *                                                      *
              * This procedure finds out how many entries there are  *
              * in the hash table and if there is more than maxhash- *
              * size it is reorganised                               * 
              *                                                      *   
              ********************************************************;

      integer field c;
      integer nr_of_en;
      c:=2;
      nr_of_en:=0;
           open(cat,4, dump1name,0);
      for i:=0 step 1 until hashentries-1 do
      begin
        setposition(cat,0,i);
        inrec6(cat,1);
        nr_of_en:=nr_of_en+cat.c;
      end;
      close(cat,true);
      if ttest then write(out,<:<10>*** size of hashtable= :>,nr_of_en);
      if nr_of_en / (hashentries * 28) > maxhashsize then reorg;
    end;
\f


    procedure rhashentry;
    begin
      k:=swoprec6(cat,0);
      if k = 0 then
      begin
         setposition(cat,0,0);
         swoprec6(cat,2);
      end;
      if k = 512 then swoprec6(cat,2);
      if k = restondumps then
      begin
        swoprec6(cat,k);
        k:=swoprec6(cat,0);
        if k = 0 then
         setposition(cat,0,0);
        swoprec6(cat,2);
        swoprec6(cat,dumpensize);
      end
      else
      swoprec6(cat,dumpensize);
    end;
\f


    procedure dumpcatupdate(nrfiles,nr,stentry);
    integer nrfiles,nr,stentry;
    begin
      integer bitno;
      comment
               *******************************************************
              *                                                     * 
              * This procedure will for the entries in the catalog  * 
              * to the tape copied that day update in dumpcat.      *
              * nrfiles: specifies how many entries that is to be   *
              * updated.                                            *
              * nr     : specifies the tapenr                       * 
              * ststentry: specifies where the entries start in the *
              * catalog.                                            *
              *                                                     *
              *******************************************************;
\f


      procedure removedumpbit;
      begin
        integer i1,i2;
        comment
                ******************************************************
                *                                                    *
                * This procedure removes the bit beloning to nr in   *
                * the whole dumpcat.                                 *
                *                                                    *
                ******************************************************;
        boolean procedure bitsat(bitnummer);integer bitnummer;
        begin
          bitsat:= if cat.wordno shift(-bitnummer) extract 1 = 1 then
             true else false;
        end;
        integer noonsegm,nremoved,word1;
        integer field place;
        boolean empty;
         if ttest then write(out,<:<10>bit=:>,bitno,
            <:<10>bitmoenster =:>,bitpattern);
        empty:=true;
        nremoved:=0;
             open(cat,4, dump1name,0);
        for i:= 0 step 1 until hashentries-1 do
        begin
          setposition(cat,0,i);
          swoprec6(cat,2);
          noonsegm:=cat.catnr;
            if ttest then write(out,<:<10>antal=:>,noonsegm);
            while noonsegm > 0 do
            begin
               rhashentry;
               while cat.catnr = -1 do rhashentry;
               empty:=true;
              if ttest then write(out,<:<10> antal1 = :>,noonsegm);
              word1:=cat.wordno;
              if bitsat(bitno) then
              cat.wordno:=exor(cat.wordno,bitpattern);
              if ttest and word1 <> cat.wordno 
              then write(out,<:word2 = :>,cat.wordno);
              for j:=1 step 1 until bittsize do
              empty:= empty and (cat.startofbitt(j) = 0);
              if empty then
              begin
                for ik:= 1 step 1 until dumpensize/2 do
                begin
                  place:=ik*2;
                  cat.place:=-1;
                end;
                nremoved:=nremoved+1;
              end;
              noonsegm:=noonsegm-1;
            end;
          if nremoved > 0 then 
          begin
            setposition(cat,0,i);
            swoprec6(cat,2);
            cat.catnr:=cat.catnr-nremoved;
            nremoved:=0;
          end;
        end;
        close(cat,true);
      end;
\f


      zone catentry(128,1,stderror);
      comment cat is a zone to dumpcat and catentry is a zone to catalog;

      integer dkey,noonsegm;
      boolean identical,found;
      if ttest then write(out,<:<10>bandnr=:>,nr);
      bitno:=(nr-1) mod 24;
      bitpattern:=1shift(bitno );
      wordno:=((nr-1)//24) +startofbit;
      if nrfiles <> 1 then removedumpbit;
      hashtsize;
           open(cat,4, dump1name,0);
           open(catentry,4, p2catname,0);
      setposition(cat,0,0);
      setposition(catentry,0,0);
      if ttest then
      begin
        write(out,<:<10> stentry=  :>,stentry,<: nrfiles = :>,nrfiles);
      end;
      for i:=1 step 1 until stentry do
      begin
        k:=inrec6(catentry,0);
        if k = 2 then inrec6(catentry,2);
       inrec6(catentry,34);
        if catentry.key = -1 then
        begin
          k:=inrec6(catentry,0);
          if k = 2 then inrec6(catentry,0);
           inrec6(catentry,34);
        end;
       end;
      i:=inrec6(catentry,0);
      if i = 2 then inrec6(catentry,2);
      for i:=1 step 1 until nrfiles do
      begin
        identical:=found:=false;
        inrec6(catentry,34);
        while catentry.key = -1 do
        begin
          k:=inrec6(catentry,0);
          if k = 2 then 
          begin
                                                inrec6(catentry,k);
            k:=inrec6(catentry,0);
          end;
          if k = 0 then goto stop;
          inrec6(catentry,34);
        end;
        dkey:=hashkey(catentry.name);
        if   ttest then
        begin
          write(out,<:<10> hash key = :>,dkey);
          write(out,<:  for the entry with name =:>);
          write(out, catentry.name);
        end;
        setposition(cat,0,dkey);
        swoprec6(cat,2);
        noonsegm:=cat.catnr;
          while noonsegm > 0 do
          begin
            rhashentry;
            while cat.catnr = -1  do rhashentry;
            identical:=cat.dname(1)=catentry.name(1) and
            cat.dname(2)=catentry.name(2) and
            cat.dbase1=catentry.lbase and
            cat.dbase2=catentry.ubase and
            cat.dumpkey extract 3 = catentry.key extract 3;
            if identical then
            begin
              found:=true;
              cat.wordno:=logor(cat.wordno,bitpattern);
              noonsegm:=0;
            end
            else
            noonsegm:=noonsegm-1;
          end;
          if -, found then
          begin
            setposition(cat,0,dkey);
            swoprec6(cat,2);
            cat.catnr:=cat.catnr+1;
            rhashentry;
            while cat.key <> -1 do rhashentry;
            cat.key:=dkey;
            cat.dname(1):=catentry.name(1);
            cat.dname(2):=catentry.name(2);
            cat.dbase1:=catentry.lbase;
            cat.dbase2:=catentry.ubase;
            cat.dumpkey:=catentry.key extract 3;
            if catentry.kind >= 0 then cat.dumpkey:=cat.dumpkey + 16;
            for j:= 1 step 1 until bittsize do cat.startofbitt(j):=0;
            cat.wordno:=bitpattern;
          end;
        end;
stop: 
      close(catentry,true);
      close(cat,true);
      i:=monitor(40)lookupentry:(cat,0,tail);
      tail(1):=hashentries;
      monitor(44)changeentry:(cat,0,tail);
    end;
\f


    procedure gettapename(taptotal);
    integer taptotal; 
    begin
      comment
              *******************************************************
              *                                                     *
              * This procedure will search the mtpool through. It   *
              * will find the oldest tape which is used to total or *
              * not depending on the variabel taptotal.             *
              *                                                     *
              *******************************************************;
      integer field antal;
      long d;
      integer tapnr,thisday,a;
      long lastdate,t1date;
      integer day,mounth,year;
      systime(1,0,r);
      wdate:=systime(2,r,r);
      day:=wdate;
      day:=day//10000;
      mounth:=wdate;
      mounth:=mounth//100 - day*100;
      year:=wdate;
      year:=year-day*10000-mounth*100;
      d:=0;a:=68;
      for i:=i while a < year do
      begin
        d:=d+(if a//4*4=a/4*4 then 366 else 365);
        a:=a+1;
      end;
      d:=d+day-1;
      if mounth > 1 then
      d:=d+(case mounth-1 
          of (31,59,90,120,151,181,212,243,273,304,334,365));
      d:=d*24*60*60;
      a:=0;
      thisday:=systime(7,a,0.0);
      lastdate:=99388604;
      antal:=2;
           open(mtrecord,4, mt1pool,0);
      i:=monitor(42)look up entry:(mtrecord,0,tail);
      if i<> 0  then error(7);
      inrec6(mtrecord,2);
      ntape:=mtrecord.antal;
      for i:= 1 step 1 until ntape do
      begin
        inrec6(mtrecord,mtrsize);
        t1date:= extend 0 add mtrecord.mtdate;
        if ttest then write(out,<:<10>mtnr = :>,mtrecord.mtnr);
        if taptotal = mtrecord.mttotal  extract 4 and
        lastdate > t1date then
        begin
          lastdate:=t1date;

          tapnr:=mtrecord.mtnr;
        end;
      end;
      setposition(mtrecord,0,0);
      today:=thisday;
      swoprec6(mtrecord,2);
      for i:=1 step 1 until tapnr do
      begin
      if ttest then write(out,<:<10>i = :>,i);
      swoprec6(mtrecord,mtrsize);
      end;
      t1tapename(1):=mtrecord.mtname(1);
      t1tapename(2):=mtrecord.mtname(2);
      tapenr:=mtrecord.mtnr;
      mtrecord.mtdate:=thisday;
      if total then mtrecord.mttotal:=1+1 shift 10 else
      mtrecord.mttotal:=0+1 shift 10;
      if ntshift > 0 then
      begin
      if mtrecord.mttotal shift (-10) extract 1 = 1 then
      mtrecord.mttotal:= mtrecord.mttotal-1 shift 10;
      end
      swoprec6(mtrecord,mtrsize);
      close(mtrecord,true);
      if ttest then
      begin
        for k:= 1 step 1 until 100 do
        begin
        write(out,<:<10>tape to use = :>, t1tapename);
        end;
      end;
    end;
\f


    long procedure dateofpdump;
    begin
      comment
              *****************************************************
              *                                                   *  
              * This procedure finds the date of the privios dump *
              * in the mtpool.                                    *
              *                                                   *  
              *****************************************************;
      zone mtrecord(128,1,stderror);
      integer field antal;
      long tdate;
      long gdate;
      antal:=2;
      gdate:=0;
           open(mtrecord,4, mtpool,0);
      if monitor(42)look up entry:(mtrecord,0,tail) <> 0 then error(7);
      setposition(mtrecord,0,0);
      inrec6(mtrecord,2);
      ntape:=mtrecord.antal;
      for i:=1 step 1 until ntape do
      begin
        inrec6(mtrecord,mtrsize);
        tdate:= extend 0 add mtrecord.mtdate;
        comment if mtrecord.mttotal >= 16  then gdate:=mtrecord.mtdate;
        if tdate > gdate 
        and mtrecord.mttotal shift (-10) extract 1 = 1 
        then
         gdate:=tdate;
      end;

      close(mtrecord,true);
      dateofpdump:=gdate;
    end;
\f



    procedure gettape(getdate,number);integer getdate, number;
    begin
      comment
              ********************************************************
              *                                                      *
              * This procedure delivers the tapename and tapenr equal*    
              * to getdate and number, which it finds in mtpool.     *
              *                                                      * 
              ********************************************************;

      zone mtrecord(128,1,stderror);
      boolean found;
      found:=false;
      if ttest then
      begin
        write(out,<:<10>pdate = :>,getdate,<:number = :>,number);
      end;
      open(mtrecord,4, mt1pool,0);
      if monitor(42)look up entry :(mtrecord,0,tail) <> 0 then error(7);
      setposition(mtrecord,0,0);
      swoprec6(mtrecord,2);
      if ttest then write(out,<:<10>getdate = :>,
          getdate,<:<10>number = :>,
        number);
      while -, found do
      begin
        swoprec6(mtrecord,mtrsize);
        if ttest then write(out,<:<10> date = :>,mtrecord.mtdate,
        <:<10> mtno =:>,mtrecord.mtno,
         <:<10>mttotal = :>,mtrecord.mttotal);
        if  mtrecord.mtdate = getdate 
        and mtrecord.mttotal shift (-10) extract 1 = 1 then
            
        begin
          found:=true;
          if mtrecord.mttotal extract 4 = 1 then 
             begin
               nomess1:=false;
               ptapename(1):= long <::>;
               ptapename(2):= long <::>;
             end else
          begin
          ptapename(1):=mtrecord.mtname(1);
          ptapename(2):=mtrecord.mtname(2);
          ptapenr:=mtrecord.mtnr;
          end;
        end;
      end;
      close(mtrecord,true);
    end;
\f


    integer procedure hashkey(hname);long array hname;
    begin
      comment
              ******************************************************
              *                                                    *
              * This procedure computes the hashkey used to insert * 
              * the entry in the dumpcat.                          *
              *                                                    *    
              ******************************************************;
      long sum,part_1_of_name,part_2_of_name;
      part_1_of_name:=  hname(1);
      part_2_of_name:=  hname(2);
      sum:=part_1_of_name+part_2_of_name;
      sum:=sum shift (-24)+sum extract (24);
      sum:=(sum extract 24 + (sum shift (-12) shift 36) ) shift (-36);
      sum:=sum extract 24;
      hashkey:= sum mod hashentries;
    end;
\f


  procedure tapedump;
   begin
     zone tape(vksegm*2*130,2,tapeproc);
     zone ptape(2*(psegm*130),2,ptapeproc);
\f


    procedure changevol(nr);
    integer nr;
    begin
      comment ******************************************************
              *                                                    *
              * This procedure will find a new tape and this is to *
              * be mounted.                                        *
              *  case nr of                                        *
              *  1: the tape is used to usual dump                 *
              *  2: the tape is a privius dumptape                 *     
              *  3: the tape is a dumttape but somthing is dumped  *
              *  on the privius tape and this has to be removed    *            
              *  from that tape.                                   *
              *                                                    *
              ******************************************************;
      integer k1;
      if ttest then 
      begin
        write(out,<:<10> number of entries saved= :>,entryno);
        write(out,<:<10> end tape is reached :>);
      end;


      monitor(72)set catalog base:(zhelp ,0,interval);
      if -,sys then
      begin
        write(out,<:<10>***end tape is reached. :>);
        goto stop;
      end else
      begin
        case nr of
        begin
          begin
            ntshift:=ntshift+1;
            newstofentry:=entryno;
            dumpcatupdate(entryno-stofentry,tapenr,stofentry);
            stofentry:=newstofentry+1;
            tapename(1):=t1tapename(1);
            tapename(2):=t1tapename(2);
            if total then gettapename(1) else gettapename(0);
            outrec6(tape,blocksize);
            changerec6(tape,100);
            tape.lo(1):=rx:=long <::> add 4 shift 24 add 16;
            tape.lo(2):= long <::> add entryno shift 24
            add (totalsegmno);
            tape.lo(3):= t1tapename(1);
            tape.lo(4):= t1tapename(2);
            for i:= 5 step 1 until 25 do tape.lo(i):= rx;
            setposition(tape,-1,0);
            close(tape,false add 1);
            tapeshift:= true;
            tapename(1):=t1tapename(1);
            tapename(2):=t1tapename(2);
            mount_med_ring(true);
            testlabel(true);
            writelabel(3);
            open(tape,modekind, t1tapename,
              1 shift 18);
            setposition(tape,1,1);
            endtape:=false;
            monitor(72)set catalogbase:(zhelp,0,entrybase);
          end;


          begin
            tntshift:=tntshift+1;
            tapename(1):=ptape.lo(3);
            tapename(2):=ptape.lo(4);
            setposition(ptape,-1,0);
            close(ptape,true);
            mount_med_ring(false);
            testlabel(false);
            open(ptape,modekind, tapename,1 shift 18);
            setposition(ptape,1,1);
            tendtape:=false;
          end;


          begin
            comment ***** backspace to privius tape;
            gettape(pdate,ntshift);
            ntshift:=ntshift-1;
            dumpcatupdate(1,tapenr,entryno);
            tapename(1):=ptapename(1);
            tapename(2):=ptapename(2);
            mount_med_ring(true);
            testlabel(true);
            close(tape,false);
            open(tape,modekind,
             t1tapename, 1 shift 18);
            setposition(tape,pfno,pbno);
            tapeshift:=false;
          end;
        end;
      end;
      monitor(72)set catalog base:(zhelp,0,entrybase);
    end;
\f


    procedure transtape;
    begin
      comment
              *******************************************************
              *                                                     *
              * This procedure  will take a file from the privius   *
              * dumptape and copy that file to the tape used now.   *
              *                                                     *
              *******************************************************;
      integer tarecordsize,tarsize,ii,ai,ik,ta1recordsize,i1;
      integer field inf2;

      begin
        inf2:=2;
         notapen:=notapen+1;
        entryno:=entryno+1;
        if ttest then write(out,<:<10>pfileno=:>,pfileno,
        <:<10>pblockno=:>,pblockno);
nexten: 
        ai:=inrec6(ptape,0);
        while ai <> 100  do
        begin
          if ai = 0 then goto finis;
          if ai mod 512 = 8 then inrec6(ptape,ai);
          ai:=inrec6(ptape,0);
        end;
        inrec6(ptape,100);
        if ptape.inf2 = 4 then 
        begin
          changevol(2);
          goto nexten;
        end;

        if ttest then
        begin
          write(out,<:<10> name = :>, ptape.taname);
          write(out,<:<10>lbase = :>,
           ptape.talbase,<: ubase= :>,ptape.taubase);
        end;
        identical:= entry.name(1) = ptape.taname(1) and
        entry.name(2) = ptape.taname(2) and
        entry.lbase = ptape.talbase and
        entry.ubase = ptape.taubase ;
        if  entry.name(1) <  ptape.taname(1) or
        (  entry.name(1) =  ptape.taname(1) and
            entry.name(2) <  ptape.taname(2) ) or
           ptape.taname(1)=  long <:mtpoo:> add 108 then
           begin
             if ttest then
             begin
               write(out,<:<10>entryname = :>,
                entry.name);
               write(out,<:<10>tapename=:>,
                ptape.taname);
             end;
             entryno:=entryno-1;
             permkey:=entry.key extract 3;
             ttail.docname(1):=entry.docname(1);
             ttail.docname(2):=entry.docname(2);
             if list then listentry(true);
             write(out,<:****:>);

             write(out,
             <:<10>*** entry does not exist on disc or previous tape:>);
             pageshift;pageshift;
             goto finis;
           end;
        if ttest then
         begin
         write(out,<:<10>navn = :>, entry.name);
        write(out,<:  lbase = :>,entry.lbase,<:ubase= :>,entry.ubase);
        end;
        if identical then
        begin
          outrec6(tape,blocksize);changerec6(tape,100);
          tofrom(tape,ptape,100);
          if ttest then write(out,<:<10>tagsegmno =:>,ptape.tasegmno);
          tape.lo(2):= long <::> add entryno shift 24 add ptape.tasegmno;
          permkey:=entry.key extract 3;
          ttail.docname(1):=entry.docname(1);
          ttail.docname(2):=entry.docname(2);
          if list then listentry(list);
          if ttest then  write(out,<:<10>tasize= :>,ptape.tasize);
          if ptape.tasize >= 0 then
          tarsize:=ptape.tasize;
          if tarsize > 0 then
        begin
          totalsegmno:=totalsegmno+tarsize;
          tarecordsize:=0;segmno:=0;
          k:=ptape.tasize//vksegm;
          for i:=0 step 1 until k-1 do
          begin
            outrec6(tape,blocksize);changerec6(tape,8);
            tape.lo(1):=long <::> add 2 shift 24 add blocksize;
            tape.lo(2):=long <::>  add entryno shift 24 add (i*vksegm);
            for ii:= 1 step 1 until vksegm do
            begin
              ai:=inrec6(ptape,0);
              if ai = 100 then
              begin
                inrec6(ptape,100);
                if ptape.inf2 = 4 then changevol(2)
                else goto finis;
                ai:=inrec6(ptape,0);
              end;
              if tarecordsize mod psegm = 0 then
              begin
                inrec6(ptape,8);
                ai:=inrec6(ptape,0);
                if ai = 100 then
                begin
                  inrec6(ptape,100);
                  if ptape.inf2 = 4 then
                  changevol(2) else goto finis;
                  ai:=inrec6(ptape,0);
                end;
              end;
              if endtape then changevol(1);
              ai:=inrec6(ptape,0);
              if ai = 100 then
              begin
                inrec6(ptape,100);
                if ptape.inf2 = 4 then
                 changevol(2) else goto finis;
                ai:=inrec6(ptape,0);
              end;
              if ai = 100 or ai = 0  then goto finis;
              if ai mod 512 = 0 then
              begin
                 inrec6(ptape,512);
                tarecordsize:=tarecordsize+1;
              outrec6(tape,512);
              for ik:= 1 step 1 until 128 do tape(ik):=ptape(ik);
           end;
           end;
         end;
         ta1recordsize:=tarsize mod vksegm;
         if ta1recordsize > 0 then
         begin
         if endtape then changevol(1);
         outrec6(tape,blocksize);
         changerec6(tape,ta1recordsize*512+8);
         tape.lo(1):=long <::> add 2 shift 24 add (ta1recordsize*512+8);
         tape.lo(2):=long <::> add entryno shift 24 add (k*vksegm);
         for ii:= 0 step 1 until ta1recordsize-1 do 
           begin
             if inrec6(ptape,0) = 8 then
             begin
             if tarecordsize mod psegm = 0 then inrec6(ptape,8);
             end;
             ai:=inrec6(ptape,0);
             if ai = 100 then
             begin
               inrec6(ptape,100);
               if ptape.inf2 = 4 then changevol(2) else goto finis;
               ai:=inrec6(ptape,0);
             end;
             if ai = 100 or ai = 0 then goto finis;
             if ai mod 512 = 0 then
             begin
               inrec6(ptape,512);
               tarecordsize:=tarecordsize+1;
             for ik:= 1 step 1 until 128 do tape(2+ii*128+ik):=ptape(ik);
            end;
           end;
         end;
       end;
          if tarsize > 0 and tarsize mod psegm <> 0 then
                pblockno:=pblockno+1;
          pblockno:=pblockno+tarsize//psegm+1;
        end
        else
        begin
          if ttest then write(out,<:<10> ta1size= :>,ptape.tasize);
          if ptape.tasize > 0 and ptape.tasize mod psegm <> 0 then
          pblockno:=pblockno+1;
          if ptape.tasize >= 0 then
          pblockno:=ptape.tasize//psegm+1+pblockno;
          if ttest then write(out,<:<10>pfil=:>,
                pfileno,<:pblo=:>,pblockno);
          ai:=inrec6(ptape,0);
          while ai <> 100 do 
          begin
            if ai = 0 then goto finis;
            if ai mod 512 = 8 then inrec6(ptape,ai);
            ai:=inrec6(ptape,0);
          end;
          goto nexten;
        end;
      end;
  pageshift;
finis:
    end <*transtape*> ;
    procedure pageshift;
    begin
      nooflisten:=nooflisten+1;
      if nooflisten >= 63 then
      begin
        nooflisten:=1;
        write(out,<:<12>:>,"sp",60,<:page :>,pagenr);
        write(out,<:<10>savelabel: :>, xlabel);
        pagenr:=pagenr+1;
      end;
    end;
\f


    procedure listentry(listspec);
    boolean listspec;
    begin
      comment
              **********************************************************
              *                                                        *
              * This procedure is used to list an entry. The procedu-  *   
              * outmodekind is used to list the kind of a filediscrip- *
              * tor.                                                   *
              *                                                        * 
              **********************************************************;
\f


      procedure outmodekind;
      begin
        integer i,modekind;
        modekind:=entry.kind;
        for i:=1 step 1 until 21 do
        begin
          if modekind=(case i of (
          <*ip*>   1 shift 23 +  0 shift 12 +  0,
          <*bs*>   1 shift 23 +  0 shift 12 +  4,
          <*tw*>   1 shift 23 +  0 shift 12 +  8,
          <*tro*>  1 shift 23 +  0 shift 12 + 10,
          <*tre*>  1 shift 23 +  2 shift 12 + 10,
          <*trn*>  1 shift 23 +  4 shift 12 + 10,
          <*trf*>  1 shift 23 +  6 shift 12 + 10,
          <*tpo*>  1 shift 23 +  0 shift 12 + 12,
          <*tpe*>  1 shift 23 +  2 shift 12 + 12,
          <*tpn*>  1 shift 23 +  4 shift 12 + 12,
          <*tpf*>  1 shift 23 +  6 shift 12 + 12,
          <*tpt*>  1 shift 23 +  8 shift 12 + 12,
          <*lp*>   1 shift 23 +  0 shift 12 + 14,
          <*crb*>  1 shift 23 +  0 shift 12 + 16,
          <*crd*>  1 shift 23 +  8 shift 12 + 16,
          <*crc*>  1 shift 23 + 10 shift 12 + 16,
          <*mto*>  1 shift 23 +  0 shift 12 + 18,
          <*mte*>  1 shift 23 +  2 shift 12 + 18,
          <*nrz*>  1 shift 23 +  4 shift 12 + 18,
          <*nrze*> 1 shift 23 +  6 shift 12 + 18,
          <*pl*>   1 shift 23 +  0 shift 12 + 20 ))
          then goto found
        end;
found:  
        if i=22 then
        begin
          write(out,<<ddddd>,modekind shift (-12),<:.:>,
          <<d>,modekind extract 12," ",
          if modekind extract 12<10 then 2 else 1);
        end
        else
        begin
          write(out,case i of (
          <:     ip  :>,
          <:     bs  :>,
          <:     tw  :>,
          <:    tro  :>,
          <:    tre  :>,
          <:    trn  :>,
          <:    trf  :>,
          <:    tpo  :>,
          <:    tpe  :>,
          <:    tpn  :>,
          <:    tpf  :>,
          <:    tpt  :>,
          <:     lp  :>,
          <:    crb  :>,
          <:    crd  :>,
          <:    crc  :>,
          <:    mto  :>,
          <:    mte  :>,
          <:    nrz  :>,
          <:   nrze  :>,
          <:     pl  :> ) );
        end
      end outmodekind;

      real k;
      integer i,j,p;
      if listspec then
      begin
        write(out,<:<10>:>);
        write(out," ",(if listmore then 11 else 0)
        -write(out, entry.name));
      end;
      if listmore then
      begin
        if entry.kind<0 then outmodekind
        else
        write(out,<<   dddd>,entry.kind," ",2);
        if sysdump then write(out,<<d>,permkey,<:.:>);
        i:=write(out, ttail.docname);
        write(out," ",12-i);
        if sysdump then
        begin
          write(out,
          <<  -ddddddd>,entry.lbase,entry.ubase);
        end;
        i:=entry.contents shift (-12);
        if i<>4 and i<32 then
        begin
          i:=entry.shortclock;
          missingclock:=false;
          if i<>0 then
          write(out,<: d.:>,<<zddddd>,
          systime(4,(if i>0 then i else i + extend 1 shift 24)
          /625*1 shift 15+12,r),
          <:.:>,<<zddd>,r/100)
        end
        else
        if entry.kind>0 then missingclock:=true;
      end;
      monitor(72,zhelp,0,entrybase);
    end listentry;
\f


    procedure dumptape;
    begin
      zone bsarea(128*2*vksegm,2,bsproc);
      long array field ta;
     integer array itail(1:20);
     integer noofbutrans;


      procedure listclock;
      begin
        integer field inf,clockadr,startext,seg;
        boolean started;



        procedure outdate;
        begin
          inf:=clockadr-2;
          write(out,<: d.:>,<<zddddd>,bsarea.inf,<:.:>);
        end;



        procedure outclock;
        begin
          write(out,<<zddd>,bsarea.clockadr/100);
          missingclock:=false;
        end;



        startext:=entry.contents extract 12+2;
        if startext>500 then
        begin
          monitor(72,zhelp,0,interval);
          write(out,<: entry inconsistent:>);
          goto exitlistclock
        end;
        setposition(bsarea,0,0);
        inrec6(bsarea,512);
        monitor(72,zhelp,0,interval);
        seg:=entry.kind-1;
        inf:=startext+2;
        clockadr:=6+bsarea.inf extract 12       
        +12*bsarea.startext extract 12
        +2*bsarea.startext shift (-12) +startext;
        if clockadr<=502 then     
        begin
          outdate;
          outclock 
        end
        else
        begin
          started:=false;
nextsegm: 
          if clockadr=504 then 
          begin
            outdate;
            started:=true 
          end;
          inf:=504;
          if bsarea.inf extract 12>500 or seg=0 then
          begin
            write(out,<: code inconsistent:>);
            goto exitlistclock
          end;
          clockadr:=clockadr-502+bsarea.inf extract 12;
          inrec6(bsarea,512); seg:=seg-1;
          if clockadr>502 then goto nextsegm;
          if -,started then outdate;
          outclock;
        end;
exitlistclock:
        monitor(72,zhelp,0,entrybase);
      end listclock;


      procedure bsproc(z,s,b);
      zone z;
      integer s,b;
      begin
        comment
                  *******************************************************
                *                                                     *
                * This block procedure is used when an entry is saved *
                * it is then tested if another process is using the   *  
                * entry.                                              *
                *                                                     *
                *******************************************************;
        monitor(72)set catalog base:(zhelp,0,interval);
        if s shift (-2) extract 1 = 1 or s shift (-5) extract 1 = 1 then
        begin
          if s shift (-5) extract 1 = 1  and b = 0 then
          begin
            monitor(72)set catalog base:(zhelp,0,entrybase);
            i:=monitor(52)create process:(bsarea,0,iarr);
            if i <> 0 and ttest then
            write(out,<:<10> result of create process =:>,i);
            if i = 0 then goto nextin;
          end;
          entryno:=entryno-1;
          if tapeshift then changevol(3)
          else
          harderror:=true;
          outrec6(tape,blocksize);

          setposition(tape,pfno,pbno);
          entry.key:=-1;
          entry.lbase:=-1;
          entry.ubase:=-1;
          totalsegmno:=totalsegmno-segmno;
          write(out,<:<10> *** entry in use:   :>);
          write(out, entryname);
          pageshift;
          if s shift (-2) extract 1 = 1 then write(out,
           <:  area reserved :>);
          if s shift (-5) extract 1 = 1 then write(out,
            <:  area not created:>);
          if ttest then
          begin
            write(out,<:<10> s=:>,s,<: b= :>,b);
          end;

        end;
        goto next;
      end;
      monitor(72)set cat base:(zhelp,0,entrybase);
      if entry.size >= 0 then
      begin


        open(bsarea,4,
                   entryname,1 shift 5 + 1 shift 2);
       proaddr:=monitor(4)process description addr:(bsarea,i,itail);
       if proaddr > 0 then
       begin
         system(5)move core area:(proaddr,itail);
         if itail(7) <> 0 then
         begin
           entry.key:=-1;
           entry.lbase:=-1;
           entry.ubase:=-1;
           write(out,<:<10>*** entry reserved:  :>,
                           entryname);
          pageshift;
          monitor(72)set cat base:(zhelp,0,interval);
           goto next;
         end;
      end;

      end;
      segmno:=0;
      i:=0;
      monitor(52)create area process:(bsarea,0,iarr);
      entryno:=entryno+1;
nextin:
      if endtape then changevol(1);
      if ttest then write(out,<:<10>pfno=:>,pfno,<:  pbno=:>,pbno);
      getposition(tape,pfno,pbno);
      outrec6(tape,blocksize);changerec6(tape,100);
      tape.lo(1):=rx:=long <::> add 1 shift 24 add 52;
      tape.lo(2):= long <::> add entryno shift 24 add
      (if entry.kind < 0 then 0 else entry.kind);
      tape.lo(3):= entry.name(1);
      tape.lo(4):=entry.name(2);
      ta:=14;
      for i:= 1 step 1 until 5 do tape.lo(4+i):= ttail.ta(i);
      permkey:= entry.key extract 3;
      tape(10):= entry.key extract 3;
      tape.lo(11):=entry.docname(1);
      tape.lo(12):=entry.docname(2);
      tape.lo(13):= long <::> add entry.lbase shift 24 add entry.ubase;
      for i:= 14 step 1 until 25 do tape.lo(i):= rx;
      if ttest then write(out,<:   size=:>,entry.kind);
      if entry.size < 0 then   goto nextentry;<*save descriptor*>
      for noofbutrans:=inrec6(bsarea,0) while noofbutrans > 2 do
      begin
        if endtape then changevol(1);
        outrec6(tape,blocksize);
        if noofbutrans+8 <> blocksize then changerec6(tape,8+noofbutrans);
        tape.lo(1):= long <::> add 2 shift 24 add (8+noofbutrans);
        tape.lo(2):=long <::> add entryno shift 24 add segmno;
        inrec6(bsarea,noofbutrans);
        raf:=8;
        tofrom(tape.raf,bsarea,noofbutrans);
        segmno:=segmno + noofbutrans//512;
        totalsegmno:=totalsegmno+ noofbutrans//512;
      end;
      tapeshift:=false;
nextentry:
      if list then listentry(true);
      if list and missingclock  and entry.size >= 0 then listclock;
      if list then pageshift;
next: 
      if entry.size >= 0 then 
      close(bsarea,true);
      if entryname(1) <> long <:incsa:> add 118 
      or entryname(2) <> long <:e:> then
      begin
         monitor(72)set cat base:(zhelp,0,entrybase);
        i:=monitor(64)remove process:(bsarea,0,iarr);
        if i <> 0 and i <> 3 and ttest then
        begin
          write(out,<:<10>entryname= :>, entry.name,
          <: result of remove = :>,i);
        end;
      end;
    end <*dumttape*>;
      comment
              *******************************************************
              *                                                     *
              * This procedure dumps the entries on tape. If an en- *
              * try can not be saved and something of that entry is *
              * saved this will be deleted and the next entry will  *
              * be saved.                                           *
              *                                                     *
              *******************************************************;
\f


      procedure outentry;
      begin
        long array field doc,tai;

        integer field bf;
        doc:=14;tai:=0;
        for i:=1 step 1 until 5 do tail.tai(i):=ttail.doc(i);
        i:=2;
        swoprec6(entry,34);
        while i <= 34 do 
        begin
          bf:=i;
          entry.bf:=ttail.bf;
          i:=i+2;
        end;
      end;
      if sys then

      open(tape,modekind, t1tapename,1 shift 18) else
      open(tape,modekind,tapename,1 shift 18);

      setposition(tape,1,1);
      open(entry,4, p2catname,0);
      setposition(entry,0,0);
      for tq1:= 1 step 1 until noofentries do
      begin
        ii:=monitor(72)set catalog base:(zhelp,0,interval);
        if ii <> 0 and ttest then write(out,
            <:<10>result of set cat base= :>,ii);
        if swoprec6(entry,0) = 2 then swoprec6(entry,2);
        i:=swoprec6(entry,0);
        if i  <> 0 then
        begin
        swoprec6(entry,34);
        if entry.key <> -1 then
        begin
          entrybase(1):=entry.lbase;
          entrybase(2):=entry.ubase;
          ii:=monitor(72)set catalog base:( zhelp,0,entrybase);
          if ii <> 0 and ttest then write(out,
            <:<10>result of set cat base=:>,ii);
          entryname(1):=entry.name(1);
          entryname(2):=entry.name(2);
          
       open(help,0, entryname,0);
       close(help,true);
          i:= monitor(76)look up head and tail:(help,0,ttail); 
           tempdoc(1):=entry.docname(1);
           tempdoc(2):=entry.docname(2);
          if i=0 and entry.lbase = ttail(2)
          and entry.ubase = ttail(3) then tofrom(entry,ttail,34);
          entry.docname(1):=tempdoc(1);
           entry.docname(2):=tempdoc(2);
          if i<>6 then
          begin
            if ttest  then
            begin
              write(out,<:<10>result of lookup entry = :>,i);
              write(out,<:<10> entryname is = :>);
              write(out, entryname);
              write(out,<: lower base= :>,
              ttail(2),<: upper base =:>,ttail(3));
            end;
            if i = 3 or
             entry.lbase <> ttail(2) or entry.ubase <> ttail(3) then
            begin
              if std and last  then
              begin
              if ptapeshift then
              begin
                ptapeshift:=false;
                open(ptape,modekind,
                 ptapename,1 shift 18);
                setposition(ptape,1,1);
              end;
                transtape;
              end else 
              begin
                 entry.key:=-1;
                 entry.lbase:=-1;
                 entry.ubase:=-1;
              end;
            end
            else
            dumptape;
          end
        end;
      end;
      end;
      monitor(72)set catalog base:(zhelp,0,interval);
      if sys then
      begin
      if ntshift > 0 then
      dumpcatupdate(entryno-stofentry,tapenr,stofentry)
      else
      dumpcatupdate(entryno,tapenr,entrystart);
      end;
      if notapen > 0 and sys then
      begin 
        setposition(ptape,-1,0);
        close(ptape,true);
      end;
      comment dump baandpool
              dumtt1name
              dump dumpcat; 
      close(entry,true);
      if sys then
      begin
        t2name(1):=0;t2name(2):=0;
        open(entry,4, t2name,0);
        tail(1):=1;
        tail(2):=1;
        tail(3):=0;tail(4):=0;tail(5):=0;
        i:= monitor(40)create entry:(entry,0,tail); 
        setposition(entry,0,0);
        entryname(1):=long <:mtpoo:> add 108;entryname(2):=long <::>;
        open(mt1record,4, mt1pool,0);

        open(help,0, entryname,0);
        close(help,true);
        monitor(48)remove entry:(help,0,tail);
        tail.tadocname(1):=mtpool(1);
        tail.tadocname(2):=mtpool(2);
        monitor(46)rename entry:(mt1record,0,tail);
        close(mt1record,true);
        open(mt1record,4, mtpool,0);
        monitor(42)lookupenty:(mt1record,0,tail);
        tail(6):=today;
        tail(9):=11 shift 12;
        monitor(44)changeentry:(mt1record,0,tail);
        monitor(76)lookup head and tail:(mt1record,0,ttail);
        swoprec6(entry,34);
        tofrom(entry,ttail,34);
        close(mt1record,true);
        if ttest then write(out,<:<10>result of look up entry1= :>,ik);
        dumptape;
        entryname(1):=long <:savec:> add 97;entryname(2):=long <:t:>;
        monitor(72)set cat base:(zhelp,0,interval);
        open(cat1,4, dump1name,0);
        open(help,0, entryname,0);
        close(help,true);
        monitor(48)remove entry:(help,0,tail);
        tail.tadocname(1):=dcname(1);
        tail.tadocname(2):=dcname(2);
        monitor(46)rename entry:(cat1,0,tail);
        close(cat1,true);
        open(cat1,4, dcname,0);
        monitor(42)lookup entry:(cat1,0,tail);
        tail(6):=today;
        tail(9):=11 shift 12;
        tail(10):=dumpensize;
        monitor(44)change entry:(cat1,0,tail);
        open(help,0, entryname,0);
        ik:=monitor(76)lookup head and tail:(help,0,ttail);

        outentry;
        close(help,true);
        if ttest then write(out,<:<10>result of lookup entry2= :>,ik);
        dumptape;
        entryname(1):=long <:tempc:>add 97;entryname(2):=long <:t:>;
        monitor(72)set cat base:(zhelp,0,interval);
        close(cat1,true);
        open(cat1,4, p2catname,0);
        open(help,0, pcatname,0);
        close(help,true);
        monitor(48)remove entry:(help,0,tail);
        tail.tadocname(1):=pcatname(1);
        tail.tadocname(2):=pcatname(2);
        monitor(46)rename entry:(cat1,0,tail);
        monitor(50)permanent entry:(cat1,3,tail);
        entrybase(1):=interval(5);entrybase(2):=interval(6);
        monitor(74)set entry base:(cat1,0,entrybase);
        close(cat1,true);
        open(cat1,4, pcatname,0);
        monitor(42)lookupentry:(cat1,0,tail);
        tail(6):=today;
        tail(9):=11 shift 12;
        if total then tail(10):=0 else
        tail(10):=entryno-2;
        monitor(44)changeentry:(cat1,0,tail);
        monitor(76)lookup head and tail:(cat1,0,ttail);
        swoprec6(entry,34);
        tofrom(entry,ttail,34);
        close(cat1,true);
        dumptape;
      end else close(help,true);
    outrec6(tape,blocksize);changerec6(tape,100);
    tape.lo(1):=rx:=long <::> add 3 shift 24 add 8;
    tape.lo(2):=long <::> add entryno shift 24 add totalsegmno;
    for i:=3 step 1 until 25 do tape.lo(i):=rx;
    setposition(tape,2,0);
    close(tape,false);
    end;
\f


    comment
            ******************************
            *                            *
            * I N I T A L I S E R I N G  *
            *                            *
            ******************************;
    open(zhelp,0,<::>,0);
    system(11)get catalog base:(0,interval);
    pagenr:=1;nooflisten:=1;
    stofentry:=0;
    lo:=0;
    mtpool(1):=long <:mtpoo:> add 108;
    mtpool(2):=long <::>;
    entryno:=0;totalsegmno:=0;
    notapen:=0;device:=0;maxhashsize:=0.5;
    nomess1:=true;
    ptapename(1):=long <::>;
    ptapename(2):=long <::>;
    endtape:=false;
    catnr:=2;dumpsize:=8;restondumps:=4;
    dbase1:=12;tadocname:=0;dbase2:=14;dname:=2;
    entrystart:=0;
    startofbit:=18;dumpkey:=16;startofbitt:=16;
    modekind:= 18 ;
    mtrsize:=16;mtno:=16;mtnr:=2;mtname:=2;mtdate:=12;mttotal:=14;
    blocksize:= 8+512*vksegm;
    sysdump:=true;
    missingclock:=false;listmore:=true;
    shortclock:=26;contents:=32;
    t1test:=false;ttest:=false;
    tname(1):=long <:dum1c:> add 97;
    tname(2):=long <:t:>;
    name:=6;kind:=16;key:=2;size:=16;
    lbase:=4;
    harderror:=false;
    taname:=8;tasegmno:=8;tasize:=8;talbase:=50;taubase:=52;
    filno:=1;ubase:=6;docname:=16;
    tempname(1):= long <:tem1c:> add 97;
    tempname(2):=long <:t:>;
    dcname(1):= long <:savec:> add 97;
    dcname(2):= long <:t:>;
    tntshift:=0;
    ntshift:=0;
    tendtape:=false;
    tapeshift:=false;
    pfileno:=1;pblockno:=1;ptapeshift:=false;
    filno:=1;ubase:=6;docname:=16;
    pfno:=1;pbno:=1;
    pdate:=dateofpdump extract 24;
    if ttest then write(out,<:<10>pdate = :>,pdate);
    if last then date:=dateofpdump;
    if ttest then write(out,<:<10> date of call = :>,date);
    comment  (* find date *);
    p2catname(1):= long <:tem2c:> add 97;
    p2catname(2):= long <:t:>;
    pcatname(1):= long <:tempc:> add 97;
    pcatname(2):=long <:t:>;
    mt1pool(1):= long <:mt1po:> add 111;
    mt1pool(2):= long <:l:>;
    open(mtrecord,4, mtpool,0);
    open(mt1record,4, mt1pool,0);
    i:=monitor(42)lookup entry:( mtrecord,0,tail);
    if i <> 0 then error(7);
    mtsize:=tail(1);
    if monitor(42)lookup entry:(mt1record,0,ttail) = 0 then
    monitor(48) remove entry:(mt1record,0,tail);
     tail(1):=mtsize;
     tail(2):=1;
     tail(3):=0;tail(4):=0;tail(5):=0;
    if monitor(40)create entry:(mt1record,0,tail) <> 0 then error(7);
    entrybase(1):=interval(5);entrybase(2):=interval(6);
   discname:=2;
   monitor(42)lookup entry:(mt1record,0,tail);
   resname(1):=tail.dname(1);resname(2):=tail.dname(2);
   i:=monitor(50)permanent entry:(mt1record,3,tail);
    if i <> 0 then
   begin
     monitor(48)remoev entry:(mt1record,0,tail);
      if ttest then write(out,<:<10>mt1record:>);
      error(5);
   end;
    i:=monitor(74)set entry base:(mt1record,0,entrybase);
    if i <> 0 then
    begin
      monitor(48)remove entry:(mt1record,0,tail);
       if ttest then write(out,<:<10>set base mt1record:>);
       error(5);
   end;
    setposition(mtrecord,0,0);setposition(mt1record,0,0);
    inrec6(mtrecord,2);bittsize:=((mtrecord.catnr-1)//24)+1;
    setposition(mtrecord,0,0);
    ik:=0;
    while  ik < mtsize do
    begin
      ik:=ik+1;
      inrec6(mtrecord,512);outrec6(mt1record,512);
      tofrom(mt1record,mtrecord,512);
    end;
    close(mtrecord,false);close(mt1record,true);
    if sys and std then
    begin
      gettape(pdate,tntshift);
      iarr(1):= ( if device = 0 then 14 shift 12 else
        32 shift 12 + 1 shift 9) ;
      iarr(2):= long <:mou:> shift (-24) extract 24;
      iarr(3):= long <:nt:> shift (-24) extract 24;
      iarr(4):= device;
      iarr(5):=ptapename(1) shift (-24) extract 24;
      iarr(6):=ptapename(1) extract 24;
      iarr(7):=ptapename(2) shift (-24) extract 24;
      iarr(8):=ptapename(2) extract 24;
      iarr(9):=0;
      iarr(10):=0;
      if nomess1 then
      system(10,0,iarr);
    end;
    if sys then
    begin
    if total then gettapename(1) else gettapename(0);
    iarr(1):=( if device = 0 then 14 shift 12 else
     32 shift 12 + 1 shift 9) ;
    iarr(2):= long <:mou:> shift (-24) extract 24;
    iarr(3):= long <:nt:> shift (-24) extract 24;
    iarr(4):= device;
    iarr(5):= t1tapename(1) shift (-24) extract 24;
    iarr(6):= t1tapename(1) extract 24;
    iarr(7):= t1tapename(2) shift (-24) extract 24;
    iarr(8):= t1tapename(2) extract 24;
    iarr(9):= 0;
    iarr(10):=0;
    system(10,0,iarr);
    end;
    if total then auxscan(0) else auxscan(date);
    open(help,0, tempname,0);
    i:=monitor(42)look up entry:(help,0,tail);
    if i = 0 then monitor(48)remove entry:(help,0,tail);
      tail(1):=c2size;
      tail(2):=1;
      tail(3):=0;tail(4):=0;tail(5):=0;
      i:=monitor(40)create entry:(help,0,tail);
      if i <> 0 then error(15);
      i:=monitor(50)permanent entry:(help,3,tail);
      if i <> 0 then error(15);
      entrybase(1):=interval(5);entrybase(2):=interval(6);
      monitor(74)set entry base :(help,0,entrybase);
    close(help,false);
    inittempcat(tempname);
    param(1):=1;param(2):=1;
    param(3):=1;param(4):=1;
    param(5):=34;
    param(6):=4;
    param(7):=0;
    keydescr(1,1):=3;keydescr(1,2):=10;
    keydescr(2,1):=3;keydescr(2,2):=14;
    keydescr(3,1):=2;keydescr(3,2):=4;
    keydescr(4,1):=2;keydescr(4,2):=6;
    sortname(1):=real <:dum1c:> add 97;
    sortname(2):=real <:t:>;
    open(help,0,tempname,0);
    monitor(42)look up entry:(help,0,tail);
    sortname(5):=tail.discname(1);
    sortname(3):=real <:tem1c:> add 97;
    sortname(4):=real <:t:>;
    sortname(6):= real <::>;
    close(help,false);
    eof:=-1;
    noofrecs:=noofentries;
    if ttest then write(out,<:<10> noofentries to save = :>,noofentries);
    vksortproc(param,keydescr,sortname,eof,noofrecs,result,explanation);
    name:=6;
    eof:=-1;
    if ttest then write(out,<:<10> noofrecs = :>,noofrecs);
    blocksize:=8+512*vksegm;
    tname(1):=long <:dum1c:> add 97;
    tname(2):=long <:t:>;
    open(help,0,tempname,0);
   entrybase(1):=interval(5);entrybase(2):=interval(6);
    monitor(42)lookup entry:(help,0,tail);
    resname(1):=tail.dname(1);resname(2):=tail.dname(2);
    i:=monitor(50)permanent entry:(help,3,tail);
    if i <> 0 then
    begin
      monitor(48)remove entry:(help,0,tail);
      if ttest then write(out,<:<10>help:>);
     error(5);
    end;
    i:=monitor(74)set entry base:(help,0,entrybase);
    if i <> 0 then
    begin
      monitor(48)remove entry:(help,0,tail);
      if ttest then write(out,<:<10>help set entry base:>);
      error(5);
   end;
    close(help,false);
    if result <> 1 then error(16);
    if sys then
    begin
    notapen:=0;
    dump1name(1):= long <:dump1:> add 99;
    dump1name(2):= long <:at:>;
    open(cat1,4, dump1name,0);
    
   open(cat,4,  dcname,0);
    i:=monitor(42)look up entry:(cat,0,tail);
    if i <> 0 then error(4);
    hashentries:=tail(1);
    dumpensize:=tail(10);
    restondumps:=510 mod dumpensize;
    if dumpensize = 0 then dumpensize:=18;
    if monitor(42)look up entry:(cat1,0,ttail) = 0 then
    monitor(48)remove entry:(cat1,0,ttail);
    tail(1):=hashentries;
    tail(2):=1;tail(3):=0;tail(4):=0;tail(5):=0;
    if monitor(40)create entry:(cat1,0,tail) <> 0 then error(7);
    entrybase(1):=interval(5);entrybase(2):=interval(6);
    monitor(42)lookup entry:(cat1,0,tail);
    resname(1):=tail.dname(1);resname(2):=tail.dname(2);
    i:=monitor(50)permanent entry:(cat1,3,tail);
    if i <> 0 then
    begin
      monitor(48)remove entry:(cat1,0,tail);
       if ttest then write(out,<:<10>cat1:>);
       error(5);
    end;
    i:=monitor(74)set entry base:(cat1,0,entrybase);
    if i <> 0 then
    begin
      monitor(48)remove entry:(cat1,0,tail);
       if ttest then write(out,<:<10>set base cat1:>);
       error(5);
    end;
    setposition(cat,0,0);
    setposition(cat1,0,0);
    i:=inrec6(cat,0);
    while i > 2 do
    begin
      inrec6(cat,i);outrec6(cat1,i);
      tofrom(cat1,cat,i);
      i:=inrec6(cat,0);
    end;
    close(cat,false);close(cat1,false);
    tapename(1):=t1tapename(1);
    tapename(2):=t1tapename(2);
    end else
    begin
      p2catname(1):= long <:tem1c:> add 97;
      p2catname(2):= long <:t:>;
    end;
    mount_med_ring(true);
    testlabel(true);
    if sys then
    begin
       if std and last then fletcatalog else
        begin
          p2catname(1):= long <:tem1c:> add 97;
          p2catname(2):= long <:t:>;
        end;

      if notapen > 0 then
      begin
        if -, ptapeshift then
        begin
          ptapeshift:=true;
          tapename(1):=ptapename(1);
          tapename(2):=ptapename(2);
          mount_med_ring(false);
          testlabel(false);
          ptapename(1):=tapename(1);
          ptapename(2):=tapename(2);
       end;
     end;
    end;
    notapen:=0;

    tapedump;
    if total then
    begin
      open(cat,4, pcatname,0);
      setposition(cat,0,0);
      outrec6(cat,510);
      for ih:=2 step 2 until 510 do cat.ih:=-1;
      close(cat,true);
      monitor(42)lookup entry:(cat,0,tail);
      tail(1):=1;
      i:=monitor(44)change entry:(cat,0,tail);
      if i <> 0 then write(out,<:<10>result of change entry = :>,i);
    end;
stop:
    tapename(1):=t1tapename(1);
    tapename(2):=t1tapename(2);
    writelabel(2);
    write(out,<:<10>   entries =:>,entryno,<:   segm=:>,totalsegmno);
    open(help,0,tempname,0);
    monitor(48)remove entry:(help,0,tail);
    close(help,false);
  end;
  savenotok:=false;
  outp:=false;
  readallparam;
  incrementdump;
halt:
  if outp then closeout;
  if savenotok then write(out,<:<10>incsave not ok<10>:>)
  else
  write(out,<:<10>incsave ok<10>:>);
  close(zhelp,true);
fpproc(7)enoprogram:(0,0,0);
end
▶EOF◀