?? RIGHT := 110 ??
MODULE ocm$generate_predictor;
*copyc osd$default_pragmats
?? PUSH (LISTEXT := ON) ??
*copyc amt$segment_pointer
*copyc amt$file_identifier
*copyc clt$file
*copyc oce$metapatch_generator_errors
*copyc oct$bytes
*copyc oct$section_directory
*copyc oct$section_list
*copyc oct$name_index_changes
*copyc oct$offset_change_list
*copyc oct$section_offset_changes
*copyc oct$single_module_predictor_hdr
*copyc oct$predictor_header
*copyc oct$predictor_size
*copyc oct$fill_sequence
*copyc occ$generate_predictor
*copyc oct$module_directory
*copyc ost$mtm_condition_codes
*copyc ost$mtm_condition_names
*copyc ost$mtm_header
*copyc ost$status_condition_code
*copyc ost$name
*copyc ost$status
*copyc pmt$program_name
*copyc llt$information_element
*copyc llt$load_module_header
*copyc llt$section_address
*copyc llt$object_text_descriptor
*copyc llt$entry_point_dictionary
*copyc llt$identification
*copyc llt$module_dictionary
*copyc llt$object_library_header
*copyc llt$library_member_header
*copyc llt$section_definition
*copyc llt$segment_definition
*copyc llt$obsolete_segment_definition
*copyc llt$command_dictionary
*copyc llt$function_dictionary
*copyc llt$help_module_dictionary
*copyc llt$message_module_dictionary
*copyc llt$panel_dictionary
?? POP ??
*copyc i#move
*copyc amp$get_segment_pointer
*copyc fsp$close_file
*copyc fsp$open_file
*copyc ocp$new_offset
*copyc ocp$convert_information_element
*copyc osp$set_status_abnormal
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc pmp$zero_out_table
*copyc pmp$get_unique_name

?? EJECT ??
?? TITLE := 'OCP$GENERATE_OL_PREDICTOR' ??
?? NEWTITLE := 'BUILD_BINDING_SECTION_CV' ??

*copyc och$build_binding_section_cv

  PROCEDURE build_binding_section_cv
    (    old_module_header: ^llt$load_module_header;
         new_module_header: ^llt$load_module_header;
         section_directory: ^oct$section_directory;
         old_file_name: fst$file_reference;
         new_file_name: fst$file_reference;
         old_ol: amt$segment_pointer;
         new_ol: amt$segment_pointer;
     VAR binding_section_offset_cv: ^oct$offset_change_list;
     VAR status: ost$status);

    VAR
      binding_section_changes: ^oct$offset_change_list,
      expected_offset: llt$section_address_range,
      expected_section_ordinal: llt$section_ordinal,
      i: integer,
      j: integer,
      length: 0 .. llc$max_binding_items,
      match_found: boolean,
      new_binding_templates: ^llt$binding_section_template,
      new_info_element_hdr: ^llt$info_element_header,
      new_information_element: llt$info_element_header,
      new_position: 0 .. llc$max_binding_items,
      old_binding_templates: ^llt$binding_section_template,
      old_info_element_hdr: ^llt$info_element_header,
      old_information_element: llt$info_element_header,
      old_position: 0 .. llc$max_binding_items,
      search_complete: boolean,
      starting_position: 0 .. llc$max_binding_items;

    status.normal := TRUE;

    old_info_element_hdr := #PTR (old_module_header^.information_element, old_ol.sequence_pointer^);
    new_info_element_hdr := #PTR (new_module_header^.information_element, new_ol.sequence_pointer^);
    IF old_info_element_hdr^.version = llc$info_element_version THEN
      old_information_element := old_info_element_hdr^;
    ELSEIF old_info_element_hdr^.version = llc$info_element_version_1_0 THEN
      ocp$convert_information_element (old_info_element_hdr, old_information_element);
    ELSE
      osp$set_status_abnormal (occ$status_id, oce$invalid_library_version, old_file_name, status);
      RETURN;
    IFEND;

    IF new_info_element_hdr^.version = llc$info_element_version THEN
      new_information_element := new_info_element_hdr^;
    ELSEIF new_info_element_hdr^.version = llc$info_element_version_1_0 THEN
      ocp$convert_information_element (new_info_element_hdr, new_information_element);
    ELSE
      osp$set_status_abnormal (occ$status_id, oce$invalid_library_version, new_file_name, status);
      RETURN;
    IFEND;

    IF (old_information_element.number_of_template_items > 0) AND
          (new_information_element.number_of_template_items > 0) THEN
      old_binding_templates := #PTR (old_information_element.binding_template_ptr, old_ol.sequence_pointer^);
      new_binding_templates := #PTR (new_information_element.binding_template_ptr, new_ol.sequence_pointer^);
      PUSH binding_section_changes: [1 .. old_information_element.number_of_template_items];
      i := 1;
      starting_position := 1;

    /search_for_match/
      FOR old_position := 1 TO old_information_element.number_of_template_items DO
        new_position := starting_position;
        match_found := FALSE;
        search_complete := FALSE;
        WHILE NOT match_found AND NOT search_complete DO
          IF old_binding_templates^ [old_position].kind = new_binding_templates^ [new_position].kind THEN
            IF old_binding_templates^ [old_position].kind = llc$current_module THEN
              IF section_directory^ [old_binding_templates^ [old_position].section_ordinal].
                    new_section_number = occ$invalid_section_ordinal THEN
                CYCLE /search_for_match/;
              IFEND;
              expected_section_ordinal := section_directory^ [old_binding_templates^ [old_position].
                    section_ordinal].new_section_number;
              expected_offset := ocp$new_offset (old_binding_templates^ [old_position].offset,
                    section_directory^ [old_binding_templates^ [old_position].section_ordinal].
                    section_offset_change_vector);
              match_found := (expected_section_ordinal = new_binding_templates^ [new_position].
                    section_ordinal) AND (expected_offset = new_binding_templates^ [new_position].offset);
            ELSE
              match_found := (old_binding_templates^ [old_position].
                    name = new_binding_templates^ [new_position].name);
            IFEND;
          IFEND;
          IF match_found THEN
            binding_section_changes^ [i].offset := (old_binding_templates^ [old_position].binding_offset DIV
                  8) * 8;
            binding_section_changes^ [i].delta := new_binding_templates^ [new_position].binding_offset -
                  old_binding_templates^ [old_position].binding_offset;
            i := i + 1;
            starting_position := new_position + 1;
            IF starting_position > new_information_element.number_of_template_items THEN
              starting_position := 1;
            IFEND;
          ELSE
            new_position := new_position + 1;
            IF new_position > new_information_element.number_of_template_items THEN
              new_position := 1;
            IFEND;
            search_complete := (new_position = starting_position);
          IFEND;
        WHILEND;
      FOREND /search_for_match/;
      length := i - 1;
      i := 1;
      WHILE (i <= length) AND (binding_section_changes^ [i].delta = 0) DO
        i := i + 1;
      WHILEND;
      IF (i = length + 1) OR (length = 0) THEN
        RETURN;
      IFEND;

      j := 2;
      i := 2;
      WHILE i <= length DO
        WHILE (i <= length) AND (binding_section_changes^ [i - 1].delta = binding_section_changes^ [i].
              delta) DO
          i := i + 1;
        WHILEND;
        IF i <= length THEN
          binding_section_changes^ [j] := binding_section_changes^ [i];
          j := j + 1;
          i := i + 1;
        IFEND;
      WHILEND;
      length := j - 1;
      ALLOCATE binding_section_offset_cv: [1 .. length];
      FOR i := 1 TO length DO
        binding_section_offset_cv^ [i] := binding_section_changes^ [i];
      FOREND;
    IFEND;
  PROCEND build_binding_section_cv;
?? EJECT ??
?? OLDTITLE ??
?? NEWTITLE := 'BUILD_COMPONENT_INDEX_CV' ??
*copyc och$build_component_index_cv

  PROCEDURE build_component_index_cv
    (    old_module_header: ^llt$load_module_header;
         new_module_header: ^llt$load_module_header;
         old_ol: amt$segment_pointer;
         new_ol: amt$segment_pointer;
     VAR length_component_index_cv: 0 .. llc$max_components;
     VAR component_index_cv: ^array [1 .. * ] of 0 .. llc$max_components;
     VAR module_directory_item: oct$module_directory_item;
     VAR status: ost$status);

    VAR
      i: 0 .. llc$max_components,
      j: 0 .. llc$max_components,
      match_found: boolean,
      new_components: ^llt$component_information,
      new_info_element: ^llt$info_element_header,
      new_information_element: llt$info_element_header,
      old_components: ^llt$component_information,
      old_info_element: ^llt$info_element_header,
      old_information_element: llt$info_element_header,
      search_complete: boolean,
      start: 0 .. llc$max_components;

    status.normal := TRUE;

    length_component_index_cv := 0;
    component_index_cv := NIL;

    old_info_element := #PTR (old_module_header^.information_element, old_ol.sequence_pointer^);
    new_info_element := #PTR (new_module_header^.information_element, new_ol.sequence_pointer^);

    IF old_info_element^.version = llc$info_element_version THEN
      old_information_element := old_info_element^;
    ELSE
      ocp$convert_information_element (old_info_element, old_information_element);
    IFEND;

    IF new_info_element^.version = llc$info_element_version THEN
      new_information_element := new_info_element^;
    ELSE
      ocp$convert_information_element (new_info_element, new_information_element);
    IFEND;

    module_directory_item.number_of_components := old_information_element.number_of_components;

    IF (old_information_element.number_of_components = 0) OR
          (new_information_element.number_of_components = 0) THEN
      RETURN;
    IFEND;

    old_components := #PTR (old_information_element.component_ptr, old_ol.sequence_pointer^);
    new_components := #PTR (new_information_element.component_ptr, new_ol.sequence_pointer^);

    ALLOCATE component_index_cv: [1 .. UPPERBOUND (old_components^)];
    start := 1;

    FOR i := 1 TO UPPERBOUND (old_components^) DO
      match_found := FALSE;
      search_complete := FALSE;
      component_index_cv^ [i] := i;
      j := start;
      WHILE NOT match_found AND NOT search_complete DO
        match_found := (old_components^ [i].name = new_components^ [j].name);
        IF match_found THEN
          component_index_cv^ [i] := j;
          start := j + 1;
          IF start > UPPERBOUND (new_components^) THEN
            start := 1;
          IFEND;
        ELSE
          j := j + 1;
          IF j > UPPERBOUND (new_components^) THEN
            j := 1;
          IFEND;
          search_complete := (j = start);
        IFEND;
      WHILEND;
    FOREND;
    length_component_index_cv := UPPERBOUND (old_components^);
  PROCEND build_component_index_cv;


?? EJECT ??
?? OLDTITLE ??
?? NEWTITLE := 'BUILD_LOAD_MODULE_PREDICTOR' ??
*copyc och$build_load_module_predictor

  PROCEDURE build_load_module_predictor
    (    old_module_header: ^llt$load_module_header;
         new_module_header: ^llt$load_module_header;
         module_name: pmt$program_name;
         old_file_name: fst$file_reference;
         new_file_name: fst$file_reference;
         p_old_ol: amt$segment_pointer;
         new_ol: amt$segment_pointer;
     VAR single_predictor: ^SEQ ( * );
     VAR single_predictor_size: oct$module_predictor_size;
     VAR module_directory_item: oct$module_directory_item;
     VAR status: ost$status);

    VAR
      attachment_options: array [1 .. 3] of fst$attachment_option,
      binding_section: llt$section_ordinal,
      binding_section_found: boolean,
      binding_section_ocv: ^oct$offset_change_list,
      change_list: ^oct$section_number_change_list,
      component_index_cv: ^array [1 .. * ] of 0 .. llc$max_components,
      end_of_sec_defs: boolean,
      i: llt$section_ordinal,
      length_component_index_cv: 0 .. llc$max_components,
      local_status: ost$status,
      module_is_bound: boolean,
      normal_socv: amt$segment_pointer,
      nsocv_fid: amt$file_identifier,
      nsocv_file_opened: boolean,
      nsocv_lfn: ost$name,
      number_section_offset_cvs: llt$section_ordinal,
      object_text_descriptor: ^llt$object_text_descriptor,
      obsolete_segment_definition: ^llt$obsolete_segment_definition,
      old_ol: amt$segment_pointer,
      section_definition: ^llt$section_definition,
      section_definitions: ^llt$object_text_descriptor,
      section_directory: ^oct$section_directory,
      section_number_cv: ^oct$new_ordinal_list,
      segment_definition: ^llt$segment_definition;

?? NEWTITLE := 'abort_handler', EJECT ??

{ PURPOSE:
{   This procedure cleans up when an abort situation occurs
{   within the block structure.
{
{ DESIGN:
{   If the file has been opened, it will be closed before the
{   the procedure returns.
{
{ NOTES:
{
{

    PROCEDURE abort_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        ignore_status: ost$status;

      IF nsocv_file_opened THEN
        fsp$close_file (nsocv_fid, ignore_status);
        nsocv_file_opened := FALSE;
      IFEND;

      IF section_number_cv <> NIL THEN
        FREE section_number_cv;
      IFEND;

      FREE section_directory;
      IF binding_section_ocv <> NIL THEN
        FREE binding_section_ocv;
      IFEND;

      IF component_index_cv <> NIL THEN
        FREE component_index_cv;
      IFEND;

    PROCEND abort_handler;

?? OLDTITLE, EJECT ??

    status.normal := TRUE;
    nsocv_file_opened := FALSE;

    old_ol := p_old_ol;

    single_predictor_size := 0;

    section_directory := NIL;
    section_number_cv := NIL;
    build_section_number_cv (old_module_header, new_module_header, old_ol,
          new_ol, section_number_cv, module_is_bound, section_directory,
          status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    module_directory_item.bound_module := module_is_bound;
    IF section_directory <> NIL THEN
      module_directory_item.last_section_ordinal :=
            UPPERBOUND (section_directory^);

      ALLOCATE change_list: [0 .. module_directory_item.last_section_ordinal];
      FOR i := 0 TO module_directory_item.last_section_ordinal DO
        change_list^ [i] := section_directory^ [i].new_section_number;
      FOREND;
      module_directory_item.section_number_change_list := change_list;
    ELSE
      module_directory_item.last_section_ordinal :=
            occ$invalid_section_ordinal;
      module_directory_item.section_number_change_list := NIL;
      RETURN;
    IFEND;

    number_section_offset_cvs := 0;
    component_index_cv := NIL;

    FOR i := 0 TO UPPERBOUND (section_directory^) DO
      section_directory^ [i].section_offset_change_vector := NIL;
    FOREND;
    length_component_index_cv := 0;

    osp$establish_block_exit_hndlr (^abort_handler);

  /main/
    BEGIN

      IF module_is_bound THEN
        pmp$get_unique_name (nsocv_lfn, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        attachment_options [1].selector := fsc$access_and_share_modes;
        attachment_options [1].access_modes.selector := fsc$specific_access_modes;
        attachment_options [1].access_modes.value := $fst$file_access_options
              [fsc$read, fsc$shorten, fsc$append, fsc$modify];
        attachment_options [1].share_modes.selector := fsc$determine_from_access_modes;
        attachment_options [2].selector := fsc$create_file;
        attachment_options [2].create_file := TRUE;
        attachment_options [3].selector := fsc$wait_for_attachment;
        attachment_options [3].wait_for_attachment.wait := osc$wait;
        attachment_options [3].wait_for_attachment.wait_time := fsc$longest_wait_time;

        nsocv_file_opened := TRUE;
        fsp$open_file (nsocv_lfn, amc$segment, ^attachment_options, NIL, NIL, NIL, NIL, nsocv_fid, status);
        IF NOT status.normal THEN
          EXIT /main/;
        IFEND;

        amp$get_segment_pointer (nsocv_fid, amc$sequence_pointer, normal_socv,
              status);
        IF NOT status.normal THEN
          EXIT /main/;
        IFEND;
        build_normal_offset_cv (old_module_header, new_module_header, new_file_name, old_file_name, old_ol,
              new_ol, normal_socv, section_directory,
              number_section_offset_cvs, status);
        IF NOT status.normal THEN
          EXIT /main/;
        IFEND;

        build_component_index_cv (old_module_header, new_module_header, old_ol,
              new_ol, length_component_index_cv, component_index_cv, module_directory_item, status);
        IF NOT status.normal THEN
          EXIT /main/;
        IFEND;

      IFEND;

      binding_section_ocv := NIL;
      IF llc$information_element IN old_module_header^.elements_defined THEN
        build_binding_section_cv (old_module_header, new_module_header,
              section_directory, old_file_name, new_file_name, old_ol, new_ol, binding_section_ocv, status);
        IF NOT status.normal THEN
          EXIT /main/;
        IFEND;
        IF binding_section_ocv <> NIL THEN
          IF llc$section_element IN old_module_header^.interpretive_header.
                elements_defined THEN
            section_definitions := #PTR (old_module_header^.
                  interpretive_header.section_definitions,
                  old_ol.sequence_pointer^);
            RESET old_ol.sequence_pointer TO section_definitions;
            end_of_sec_defs := FALSE;
            binding_section_found := FALSE;
            REPEAT
              NEXT object_text_descriptor IN old_ol.sequence_pointer;
              CASE object_text_descriptor^.kind OF
              = llc$section_definition, llc$allotted_section_definition,
                    llc$unallocated_common_block =
                NEXT section_definition IN old_ol.sequence_pointer;
                IF section_definition^.kind = llc$binding_section THEN
                  binding_section := section_definition^.section_ordinal;
                  binding_section_found := TRUE;
                IFEND;
              = llc$segment_definition, llc$allotted_segment_definition =
                NEXT segment_definition IN old_ol.sequence_pointer;
                IF segment_definition^.section_definition.kind =
                      llc$binding_section THEN
                  binding_section := segment_definition^.section_definition.
                        section_ordinal;
                  binding_section_found := TRUE;
                IFEND;
              = llc$obsolete_segment_definition,
                    llc$obsolete_allotted_seg_def =
                NEXT obsolete_segment_definition IN old_ol.sequence_pointer;
                IF obsolete_segment_definition^.section_definition.kind =
                      llc$binding_section THEN
                  binding_section := obsolete_segment_definition^.
                        section_definition.section_ordinal;
                  binding_section_found := TRUE;
                IFEND;
              ELSE
                end_of_sec_defs := TRUE;
              CASEND;
            UNTIL end_of_sec_defs OR binding_section_found;
          IFEND;
        IFEND;
      IFEND;

      construct_module_predictor (module_name, number_section_offset_cvs,
            section_number_cv, normal_socv, binding_section_ocv,
            binding_section, component_index_cv, length_component_index_cv,
            single_predictor, single_predictor_size);

    END /main/;

    IF section_number_cv <> NIL THEN
      FREE section_number_cv;
    IFEND;

    FREE section_directory;
    IF binding_section_ocv <> NIL THEN
      FREE binding_section_ocv;
    IFEND;

    IF component_index_cv <> NIL THEN
      FREE component_index_cv;
    IFEND;

    IF nsocv_file_opened THEN
      fsp$close_file (nsocv_fid, local_status);
      nsocv_file_opened := FALSE;
      IF status.normal AND (NOT local_status.normal) THEN
        status := local_status;
      IFEND;
    IFEND;

    osp$disestablish_cond_handler;

  PROCEND build_load_module_predictor;

?? EJECT ??
?? OLDTITLE ??
?? NEWTITLE := 'BUILD_MESSAGE_PREDICTOR' ??
*copyc och$build_message_predictor

  PROCEDURE build_message_predictor
    (    old_message_header: ^llt$library_member_header;
         new_message_header: ^llt$library_member_header,
         module_name: pmt$program_name;
         p_old_ol: amt$segment_pointer;
         p_new_ol: amt$segment_pointer;
     VAR single_predictor: ^SEQ ( * );
     VAR single_predictor_size: oct$module_predictor_size;
     VAR status: ost$status);

    VAR
      change_length: oct$max_offset_changes,
      found: boolean,
      index: oct$max_offset_changes,
      k: ost$status_condition_code,
      l: ost$status_condition_code,
      message_name_index_changes: ^oct$name_index_changes,
      message_offset_changes: ^oct$offset_change_list,
      message_template_cv: ^oct$offset_change_list,
      new: ost$status_condition_code,
      new_condition_codes: ^ost$mtm_condition_codes,
      new_condition_names: ^ost$mtm_condition_names,
      new_member: ^SEQ ( * ),
      new_member_seq: ^SEQ ( * ),
      new_mtm_header: ^ost$mtm_header,
      new_ol: amt$segment_pointer,
      new_template: ^ost$message_template,
      old: ost$status_condition_code,
      old_condition_codes: ^ost$mtm_condition_codes,
      old_condition_names: ^ost$mtm_condition_names,
      old_member: ^SEQ ( * ),
      old_member_seq: ^SEQ ( * ),
      old_mtm_header: ^ost$mtm_header,
      old_ol: amt$segment_pointer,
      old_template: ^ost$message_template,
      predictor_header: ^oct$single_module_predictor_hdr;

    status.normal := TRUE;

    new_ol := p_new_ol;
    old_ol := p_old_ol;

    RESET single_predictor;
    NEXT predictor_header IN single_predictor;
    predictor_header^.predictor_size := #SIZE (predictor_header^);

    index := 1;
    old_member := #PTR (old_message_header^.member, old_ol.sequence_pointer^);
    new_member := #PTR (new_message_header^.member, new_ol.sequence_pointer^);

    RESET old_ol.sequence_pointer TO old_member;
    RESET new_ol.sequence_pointer TO new_member;

    NEXT old_member_seq: [[REP old_message_header^.member_size OF cell]] IN old_ol.sequence_pointer;
    NEXT new_member_seq: [[REP new_message_header^.member_size OF cell]] IN new_ol.sequence_pointer;

    RESET old_member_seq;
    RESET new_member_seq;

    NEXT old_mtm_header IN old_member_seq;
    NEXT new_mtm_header IN new_member_seq;

    ALLOCATE message_offset_changes: [1 .. old_mtm_header^.number_of_names + 1];
    message_offset_changes^ [index].offset := #OFFSET (old_member);
    message_offset_changes^ [index].delta := #OFFSET (new_member) - #OFFSET (old_member);
    index := index + 1;

    IF old_mtm_header^.number_of_codes > 0 THEN
      NEXT old_condition_codes: [0 .. old_mtm_header^.number_of_codes - 1] IN old_member_seq;
      NEXT new_condition_codes: [0 .. new_mtm_header^.number_of_codes - 1] IN new_member_seq;

      NEXT old_condition_names: [0 .. old_mtm_header^.number_of_names - 1] IN old_member_seq;
      NEXT new_condition_names: [0 .. new_mtm_header^.number_of_names - 1] IN new_member_seq;

      NEXT message_name_index_changes: [0 .. old_mtm_header^.number_of_codes - 1] IN single_predictor;
      FOR k := 0 TO UPPERBOUND (message_name_index_changes^) DO
        message_name_index_changes^ [k] := osc$max_status_condition_code;
      FOREND;

      old := 0;
      new := 0;
      WHILE (old <= old_mtm_header^.number_of_codes - 1) AND (new <= new_mtm_header^.number_of_codes - 1) DO
        found := FALSE;
        WHILE NOT found AND (old <= old_mtm_header^.number_of_codes - 1) AND
              (new <= new_mtm_header^.number_of_codes - 1) DO
          IF old_condition_codes^ [old].code = new_condition_codes^ [new].code THEN
            found := TRUE;
          ELSEIF old_condition_codes^ [old].code < new_condition_codes^ [new].code THEN
            old := old + 1;
          ELSEIF old_condition_codes^ [old].code > new_condition_codes^ [new].code THEN
            new := new + 1;
          IFEND;
        WHILEND;

        IF found THEN
          k := old_condition_codes^ [old].name_index;
          l := new_condition_codes^ [new].name_index;
          message_name_index_changes^ [k] := l;
          old_template := #PTR (old_condition_names^ [k].template, old_member_seq^);
          new_template := #PTR (new_condition_names^ [l].template, new_member_seq^);
          message_offset_changes^ [index].offset := #OFFSET (old_template);
          message_offset_changes^ [index].delta := (#OFFSET (new_template) - #OFFSET (new_member_seq)) -
                (#OFFSET (old_template) - #OFFSET (old_member_seq));
          index := index + 1;
          old := old + 1;
          new := new + 1;
        IFEND;
      WHILEND;

      predictor_header^.last_name_index := old_mtm_header^.number_of_codes - 1;
      predictor_header^.predictor_size := predictor_header^.predictor_size +
            #SIZE (message_name_index_changes^);

      change_length := index - 1;
      compress_change_vector (message_offset_changes, change_length);

      IF change_length > 0 THEN
        predictor_header^.length_message_template_cv := change_length;
        NEXT message_template_cv: [1 .. change_length] IN single_predictor;
        message_template_cv^ := message_offset_changes^;
        predictor_header^.message_template_cv := #REL (message_template_cv, single_predictor^);
        predictor_header^.predictor_size := predictor_header^.predictor_size + #SIZE (message_template_cv^);
        predictor_header^.module_name := module_name;
        predictor_header^.kind := llc$message_module;
      IFEND;
    IFEND;

    IF predictor_header^.predictor_size > #SIZE (predictor_header^) THEN
      single_predictor_size := predictor_header^.predictor_size;
    ELSE
      single_predictor_size := 0;
    IFEND;

    FREE message_offset_changes;

  PROCEND build_message_predictor;
?? EJECT ??
?? OLDTITLE ??
?? NEWTITLE := 'BUILD_MOD_DICTIONARY_OCV' ??
*copyc och$build_mod_dictionary_ocv

  PROCEDURE build_mod_dictionary_ocv
    (    module_directory: ^oct$module_directory;
         old_module_dictionary: ^llt$module_dictionary;
         new_module_dictionary: ^llt$module_dictionary;
     VAR old_ol: amt$segment_pointer;
     VAR new_ol: amt$segment_pointer;
     VAR predictor: amt$segment_pointer;
     VAR status: ost$status);

    VAR
      change_count: 0 .. llc$max_modules_in_library,
      change_length: 0 .. llc$max_modules_in_library,
      end_of_old_sec_defs: boolean,
      expected_new_section_ordinal: 0 .. llc$max_modules_in_library,
      fill: ^oct$fill_sequence,
      first_new_section_definition: ^llt$object_text_descriptor,
      first_old_section_definition: ^llt$object_text_descriptor,
      i: 0 .. llc$max_modules_in_library,
      j: 0 .. llc$max_modules_in_library,
      length: integer,
      match_found: boolean,
      mod_dictionary_ocv: ^oct$offset_change_list,
      module_offset_cv: ^oct$offset_change_list,
      new_applic_command_header: ^llt$application_member_header,
      new_applic_program_header: ^llt$application_member_header,
      new_binding_template_ptr: ^llt$binding_section_template,
      new_command_header: ^llt$library_member_header,
      new_component_ptr: ^llt$component_information,
      new_entry_points: ^llt$object_text_descriptor,
      new_external_linkages: ^llt$object_text_descriptor,
      new_function_header: ^llt$library_member_header,
      new_info_element_hdr: ^llt$info_element_header,
      new_information_element: llt$info_element_header,
      new_interpretive_element: ^llt$object_text_descriptor,
      new_library_list: ^llt$object_text_descriptor,
      new_load_module_hdr: ^llt$load_module_header,
      new_map: ^llt$section_map_items,
      new_message_header: ^llt$library_member_header,
      new_mod_number: 0 .. llc$max_modules_in_library,
      new_object_text_descriptor: ^llt$object_text_descriptor,
      new_panel_header: ^llt$library_member_header,
      new_ppu_header: ^llt$object_text_descriptor,
      new_program_header: ^llt$library_member_header,
      new_relocation_ptr: ^llt$relocation,
      new_section_def: llt$section_ordinal,
      new_section_definition: ^llt$section_definition,
      new_section_maps: ^llt$section_maps,
      new_transfer_symbol: ^llt$object_text_descriptor,
      obsolete_segment_definition: ^llt$obsolete_segment_definition,
      old_applic_command_header: ^llt$application_member_header,
      old_applic_program_header: ^llt$application_member_header,
      old_binding_template_ptr: ^llt$binding_section_template,
      old_command_header: ^llt$library_member_header,
      old_component_ptr: ^llt$component_information,
      old_entry_points: ^llt$object_text_descriptor,
      old_external_linkages: ^llt$object_text_descriptor,
      old_function_header: ^llt$library_member_header,
      old_info_element_hdr: ^llt$info_element_header,
      old_information_element: llt$info_element_header,
      old_interpretive_element: ^llt$object_text_descriptor,
      old_library_list: ^llt$object_text_descriptor,
      old_load_module_hdr: ^llt$load_module_header,
      old_map: ^llt$section_map_items,
      old_message_header: ^llt$library_member_header,
      old_mod_number: 0 .. llc$max_modules_in_library,
      old_object_text_descriptor: ^llt$object_text_descriptor,
      old_panel_header: ^llt$library_member_header,
      old_ppu_header: ^llt$object_text_descriptor,
      old_program_header: ^llt$library_member_header,
      old_relocation_ptr: ^llt$relocation,
      old_section_definition: ^llt$section_definition,
      old_section_maps: ^llt$section_maps,
      old_transfer_symbol: ^llt$object_text_descriptor,
      predictor_header: ^oct$predictor_header,
      search_complete: boolean,
      segment_definition: ^llt$segment_definition,
      starting_section_def: llt$section_ordinal,
      text: string (osc$max_string_size);

    status.normal := TRUE;

    change_count := 1;
    PUSH module_offset_cv: [1 .. llc$max_section_ordinal];
    FOR old_mod_number := 1 TO UPPERBOUND (module_directory^) DO
      new_mod_number := module_directory^ [old_mod_number].new_module_number;
      IF new_mod_number <> 0 THEN
        CASE old_module_dictionary^ [old_mod_number].kind OF
        = llc$ppu_object_module =
          old_ppu_header := #PTR (old_module_dictionary^ [old_mod_number].ppu_header,
                old_ol.sequence_pointer^);
          new_ppu_header := #PTR (new_module_dictionary^ [new_mod_number].ppu_header,
                new_ol.sequence_pointer^);
          module_offset_cv^ [change_count].offset := #OFFSET (old_ppu_header);
          module_offset_cv^ [change_count].delta := #OFFSET (new_ppu_header) - #OFFSET (old_ppu_header);
          change_count := change_count + 1;

        = llc$program_description =
          old_program_header := #PTR (old_module_dictionary^ [old_mod_number].program_header,
                old_ol.sequence_pointer^);
          new_program_header := #PTR (new_module_dictionary^ [new_mod_number].program_header,
                new_ol.sequence_pointer^);
          module_offset_cv^ [change_count].offset := #OFFSET (old_program_header);
          module_offset_cv^ [change_count].delta := #OFFSET (new_program_header) -
                #OFFSET (old_program_header);
          change_count := change_count + 1;

        = llc$command_procedure =
          old_command_header := #PTR (old_module_dictionary^ [old_mod_number].command_header,
                old_ol.sequence_pointer^);
          new_command_header := #PTR (new_module_dictionary^ [new_mod_number].command_header,
                new_ol.sequence_pointer^);
          module_offset_cv^ [change_count].offset := #OFFSET (old_command_header);
          module_offset_cv^ [change_count].delta := #OFFSET (new_command_header) -
                #OFFSET (old_command_header);
          change_count := change_count + 1;

        = llc$applic_program_description =
          old_applic_program_header := #PTR (old_module_dictionary^ [old_mod_number].applic_program_header,
                old_ol.sequence_pointer^);
          new_applic_program_header := #PTR (new_module_dictionary^ [new_mod_number].applic_program_header,
                new_ol.sequence_pointer^);
          module_offset_cv^ [change_count].offset := #OFFSET (old_applic_program_header);
          module_offset_cv^ [change_count].delta := #OFFSET (new_applic_program_header) -
                #OFFSET (old_applic_program_header);
          change_count := change_count + 1;

        = llc$applic_command_procedure =
          old_applic_command_header := #PTR (old_module_dictionary^ [old_mod_number].applic_command_header,
                old_ol.sequence_pointer^);
          new_applic_command_header := #PTR (new_module_dictionary^ [new_mod_number].applic_command_header,
                new_ol.sequence_pointer^);
          module_offset_cv^ [change_count].offset := #OFFSET (old_applic_command_header);
          module_offset_cv^ [change_count].delta := #OFFSET (new_applic_command_header) -
                #OFFSET (old_applic_command_header);
          change_count := change_count + 1;

        = llc$function_procedure =
          old_function_header := #PTR (old_module_dictionary^ [old_mod_number].function_header,
                old_ol.sequence_pointer^);
          new_function_header := #PTR (new_module_dictionary^ [new_mod_number].function_header,
                new_ol.sequence_pointer^);
          module_offset_cv^ [change_count].offset := #OFFSET (old_function_header);
          module_offset_cv^ [change_count].delta := #OFFSET (new_function_header) -
                #OFFSET (old_function_header);
          change_count := change_count + 1;

        = llc$message_module =
          old_message_header := #PTR (old_module_dictionary^ [old_mod_number].message_header,
                old_ol.sequence_pointer^);
          new_message_header := #PTR (new_module_dictionary^ [new_mod_number].message_header,
                new_ol.sequence_pointer^);
          module_offset_cv^ [change_count].offset := #OFFSET (old_message_header);
          module_offset_cv^ [change_count].delta := #OFFSET (new_message_header) -
                #OFFSET (old_message_header);
          change_count := change_count + 1;

        = llc$panel_module =
          old_panel_header := #PTR (old_module_dictionary^ [old_mod_number].panel_header,
                old_ol.sequence_pointer^);
          new_panel_header := #PTR (new_module_dictionary^ [new_mod_number].panel_header,
                new_ol.sequence_pointer^);
          module_offset_cv^ [change_count].offset := #OFFSET (old_panel_header);
          module_offset_cv^ [change_count].delta := #OFFSET (new_panel_header) - #OFFSET (old_panel_header);
          change_count := change_count + 1;

        = llc$load_module =
          old_load_module_hdr := #PTR (old_module_dictionary^ [old_mod_number].module_header,
                old_ol.sequence_pointer^);
          new_load_module_hdr := #PTR (new_module_dictionary^ [new_mod_number].module_header,
                new_ol.sequence_pointer^);
          module_offset_cv^ [change_count].offset := #OFFSET (old_load_module_hdr);
          module_offset_cv^ [change_count].delta := #OFFSET (new_load_module_hdr) -
                #OFFSET (old_load_module_hdr);
          change_count := change_count + 1;

          IF llc$interpretive_element IN old_load_module_hdr^.elements_defined THEN
            old_interpretive_element := #PTR (old_load_module_hdr^.interpretive_element,
                  old_ol.sequence_pointer^);
            new_interpretive_element := #PTR (new_load_module_hdr^.interpretive_element,
                  new_ol.sequence_pointer^);
            module_offset_cv^ [change_count].offset := #OFFSET (old_interpretive_element);
            module_offset_cv^ [change_count].delta := #OFFSET (new_interpretive_element) -
                  module_offset_cv^ [change_count].offset;
            change_count := change_count + 1;

            IF llc$library_element IN old_load_module_hdr^.interpretive_header.elements_defined THEN
              old_library_list := #PTR (old_load_module_hdr^.interpretive_header.library_list,
                    old_ol.sequence_pointer^);
              new_library_list := #PTR (new_load_module_hdr^.interpretive_header.library_list,
                    new_ol.sequence_pointer^);
              module_offset_cv^ [change_count].offset := #OFFSET (old_library_list);
              module_offset_cv^ [change_count].delta := #OFFSET (new_library_list) -
                    module_offset_cv^ [change_count].offset;
              change_count := change_count + 1;
            IFEND;

            IF llc$section_element IN old_load_module_hdr^.interpretive_header.elements_defined THEN
              first_old_section_definition := #PTR (old_load_module_hdr^.interpretive_header.
                    section_definitions, old_ol.sequence_pointer^);
              first_new_section_definition := #PTR (new_load_module_hdr^.interpretive_header.
                    section_definitions, new_ol.sequence_pointer^);
              module_offset_cv^ [change_count].offset := #OFFSET (first_old_section_definition);
              module_offset_cv^ [change_count].delta := #OFFSET (first_new_section_definition) -
                    module_offset_cv^ [change_count].offset;
              change_count := change_count + 1;

              end_of_old_sec_defs := FALSE;
              RESET old_ol.sequence_pointer TO first_old_section_definition;

            /find_matching_allotted_section/
              REPEAT
                NEXT old_object_text_descriptor IN old_ol.sequence_pointer;
                CASE old_object_text_descriptor^.kind OF
                = llc$section_definition, llc$unallocated_common_block =
                  NEXT old_section_definition IN old_ol.sequence_pointer;
                = llc$allotted_section_definition =
                  NEXT old_section_definition IN old_ol.sequence_pointer;
                  IF (module_directory^ [old_mod_number].section_number_change_list^
                        [old_section_definition^.section_ordinal] = occ$invalid_section_ordinal) THEN
                    CYCLE /find_matching_allotted_section/;
                  IFEND;
                  RESET new_ol.sequence_pointer TO first_new_section_definition;
                  match_found := FALSE;
                  search_complete := FALSE;
                  expected_new_section_ordinal := module_directory^ [old_mod_number].
                        section_number_change_list^ [old_section_definition^.section_ordinal];
                  REPEAT
                    NEXT new_object_text_descriptor IN new_ol.sequence_pointer;
                    CASE new_object_text_descriptor^.kind OF
                    = llc$section_definition, llc$unallocated_common_block =
                      NEXT new_section_definition IN new_ol.sequence_pointer;
                    = llc$allotted_section_definition =
                      NEXT new_section_definition IN new_ol.sequence_pointer;
                      match_found := (expected_new_section_ordinal =
                            new_section_definition^.section_ordinal) AND
                            (new_section_definition^.kind = old_section_definition^.kind) AND
                            (new_section_definition^.access_attributes =
                            old_section_definition^.access_attributes) AND
                            (new_section_definition^.name = old_section_definition^.name);
                      IF match_found THEN
                        module_offset_cv^ [change_count].offset := old_object_text_descriptor^.
                              allotted_section;
                        module_offset_cv^ [change_count].delta := new_object_text_descriptor^.
                              allotted_section - old_object_text_descriptor^.allotted_section;
                        change_count := change_count + 1;
                      IFEND;
                    ELSE
                      search_complete := TRUE;
                    CASEND;
                  UNTIL match_found OR search_complete;
                = llc$segment_definition =
                  NEXT segment_definition IN old_ol.sequence_pointer;
                = llc$obsolete_segment_definition =
                  NEXT obsolete_segment_definition IN old_ol.sequence_pointer;
                = llc$allotted_segment_definition =
                  NEXT segment_definition IN old_ol.sequence_pointer;
                  old_section_definition := ^segment_definition^.section_definition;
                  IF (module_directory^ [old_mod_number].section_number_change_list^
                        [old_section_definition^.section_ordinal] = occ$invalid_section_ordinal) THEN
                    CYCLE /find_matching_allotted_section/;
                  IFEND;
                  RESET new_ol.sequence_pointer TO first_new_section_definition;
                  match_found := FALSE;
                  search_complete := FALSE;
                  expected_new_section_ordinal := module_directory^ [old_mod_number].
                        section_number_change_list^ [old_section_definition^.section_ordinal];
                  REPEAT
                    NEXT new_object_text_descriptor IN new_ol.sequence_pointer;
                    CASE new_object_text_descriptor^.kind OF
                    = llc$segment_definition =
                      NEXT segment_definition IN new_ol.sequence_pointer;
                    = llc$allotted_segment_definition =
                      NEXT segment_definition IN new_ol.sequence_pointer;
                      new_section_definition := ^segment_definition^.section_definition;
                      match_found := (expected_new_section_ordinal =
                            new_section_definition^.section_ordinal) AND
                            (new_section_definition^.kind = old_section_definition^.kind) AND
                            (new_section_definition^.access_attributes =
                            old_section_definition^.access_attributes) AND
                            (new_section_definition^.name = old_section_definition^.name);
                      IF match_found THEN
                        module_offset_cv^ [change_count].offset := old_object_text_descriptor^.
                              allotted_segment;
                        module_offset_cv^ [change_count].delta := new_object_text_descriptor^.
                              allotted_segment - old_object_text_descriptor^.allotted_segment;
                        change_count := change_count + 1;
                      IFEND;
                    ELSE
                      search_complete := TRUE;
                    CASEND;
                  UNTIL match_found OR search_complete;
                = llc$obsolete_allotted_seg_def =
                  NEXT obsolete_segment_definition IN old_ol.sequence_pointer;
                  old_section_definition := ^obsolete_segment_definition^.section_definition;
                  IF (module_directory^ [old_mod_number].section_number_change_list^
                        [old_section_definition^.section_ordinal] = occ$invalid_section_ordinal) THEN
                    CYCLE /find_matching_allotted_section/;
                  IFEND;
                  RESET new_ol.sequence_pointer TO first_new_section_definition;
                  match_found := FALSE;
                  search_complete := FALSE;
                  expected_new_section_ordinal := module_directory^ [old_mod_number].
                        section_number_change_list^ [old_section_definition^.section_ordinal];
                  REPEAT
                    NEXT new_object_text_descriptor IN new_ol.sequence_pointer;
                    CASE new_object_text_descriptor^.kind OF
                    = llc$obsolete_segment_definition =
                      NEXT obsolete_segment_definition IN new_ol.sequence_pointer;
                    = llc$obsolete_allotted_seg_def =
                      NEXT obsolete_segment_definition IN new_ol.sequence_pointer;
                      new_section_definition := ^obsolete_segment_definition^.section_definition;
                      match_found := (expected_new_section_ordinal =
                            new_section_definition^.section_ordinal) AND
                            (new_section_definition^.kind = old_section_definition^.kind) AND
                            (new_section_definition^.access_attributes =
                            old_section_definition^.access_attributes) AND
                            (new_section_definition^.name = old_section_definition^.name);
                      IF match_found THEN
                        module_offset_cv^ [change_count].offset := old_object_text_descriptor^.
                              allotted_segment;
                        module_offset_cv^ [change_count].delta := new_object_text_descriptor^.
                              allotted_segment - old_object_text_descriptor^.allotted_segment;
                        change_count := change_count + 1;
                      IFEND;
                    ELSE
                      search_complete := TRUE;
                    CASEND;
                  UNTIL match_found OR search_complete;
                ELSE
                  end_of_old_sec_defs := TRUE;
                CASEND;
              UNTIL end_of_old_sec_defs;
            IFEND;

            IF llc$entry_point_element IN old_load_module_hdr^.interpretive_header.elements_defined THEN
              old_entry_points := #PTR (old_load_module_hdr^.interpretive_header.entry_points,
                    old_ol.sequence_pointer^);
              new_entry_points := #PTR (new_load_module_hdr^.interpretive_header.entry_points,
                    new_ol.sequence_pointer^);
              module_offset_cv^ [change_count].offset := #OFFSET (old_entry_points);
              module_offset_cv^ [change_count].delta := #OFFSET (new_entry_points) -
                    module_offset_cv^ [change_count].offset;
              change_count := change_count + 1;
            IFEND;

            IF llc$external_element IN old_load_module_hdr^.interpretive_header.elements_defined THEN
              old_external_linkages := #PTR (old_load_module_hdr^.interpretive_header.external_linkages,
                    old_ol.sequence_pointer^);
              new_external_linkages := #PTR (new_load_module_hdr^.interpretive_header.external_linkages,
                    new_ol.sequence_pointer^);
              module_offset_cv^ [change_count].offset := #OFFSET (old_external_linkages);
              module_offset_cv^ [change_count].delta := #OFFSET (new_external_linkages) -
                    module_offset_cv^ [change_count].offset;
              change_count := change_count + 1;
            IFEND;

            IF llc$transfer_symbol_element IN old_load_module_hdr^.interpretive_header.elements_defined THEN
              old_transfer_symbol := #PTR (old_load_module_hdr^.interpretive_header.transfer_symbol,
                    old_ol.sequence_pointer^);
              new_transfer_symbol := #PTR (new_load_module_hdr^.interpretive_header.transfer_symbol,
                    new_ol.sequence_pointer^);
              module_offset_cv^ [change_count].offset := #OFFSET (old_transfer_symbol);
              module_offset_cv^ [change_count].delta := #OFFSET (new_transfer_symbol) -
                    module_offset_cv^ [change_count].offset;
              change_count := change_count + 1;
            IFEND;
          IFEND;

          IF llc$information_element IN old_load_module_hdr^.elements_defined THEN
            old_info_element_hdr := #PTR (old_load_module_hdr^.information_element, old_ol.sequence_pointer^);
            new_info_element_hdr := #PTR (new_load_module_hdr^.information_element, new_ol.sequence_pointer^);
            module_offset_cv^ [change_count].offset := #OFFSET (old_info_element_hdr);
            module_offset_cv^ [change_count].delta := #OFFSET (new_info_element_hdr) -
                  #OFFSET (old_info_element_hdr);
            change_count := change_count + 1;

            IF old_info_element_hdr^.version = llc$info_element_version THEN
              old_information_element := old_info_element_hdr^;
            ELSE
              ocp$convert_information_element (old_info_element_hdr, old_information_element);
            IFEND;

            IF new_info_element_hdr^.version = llc$info_element_version THEN
              new_information_element := new_info_element_hdr^;
            ELSE
              ocp$convert_information_element (new_info_element_hdr, new_information_element);
            IFEND;

            IF old_information_element.number_of_rel_items > 0 THEN
              module_directory^ [old_mod_number].number_of_rel_items := old_information_element.
                    number_of_rel_items;
              old_relocation_ptr := #PTR (old_information_element.relocation_ptr, old_ol.sequence_pointer^);
              new_relocation_ptr := #PTR (new_information_element.relocation_ptr, new_ol.sequence_pointer^);
              module_offset_cv^ [change_count].offset := #OFFSET (old_relocation_ptr);
              module_offset_cv^ [change_count].delta := #OFFSET (new_relocation_ptr) -
                    module_offset_cv^ [change_count].offset;
              change_count := change_count + 1;
            IFEND;

            IF old_information_element.number_of_components > 0 THEN
              old_component_ptr := #PTR (old_information_element.component_ptr, old_ol.sequence_pointer^);
              new_component_ptr := #PTR (new_information_element.component_ptr, new_ol.sequence_pointer^);
              module_offset_cv^ [change_count].offset := #OFFSET (old_component_ptr);
              module_offset_cv^ [change_count].delta := #OFFSET (new_component_ptr) -
                    module_offset_cv^ [change_count].offset;
              change_count := change_count + 1;
            IFEND;

            IF old_information_element.number_of_template_items > 0 THEN
              old_binding_template_ptr := #PTR (old_information_element.binding_template_ptr,
                    old_ol.sequence_pointer^);
              new_binding_template_ptr := #PTR (new_information_element.binding_template_ptr,
                    new_ol.sequence_pointer^);
              module_offset_cv^ [change_count].offset := #OFFSET (old_binding_template_ptr);
              module_offset_cv^ [change_count].delta := #OFFSET (new_binding_template_ptr) -
                    module_offset_cv^ [change_count].offset;
              change_count := change_count + 1;
            IFEND;

            IF old_information_element.number_of_section_maps > 0 THEN
              old_section_maps := #PTR (old_information_element.section_maps, old_ol.sequence_pointer^);
              new_section_maps := #PTR (new_information_element.section_maps, new_ol.sequence_pointer^);
              module_offset_cv^ [change_count].offset := #OFFSET (old_section_maps);
              module_offset_cv^ [change_count].delta := #OFFSET (new_section_maps) -
                    #OFFSET (old_section_maps);
              change_count := change_count + 1;
              FOR i := 0 TO old_information_element.number_of_section_maps - 1 DO
                j := module_directory^ [old_mod_number].section_number_change_list^ [i];
                old_map := #PTR (old_section_maps^ [i].map, old_ol.sequence_pointer^);
                new_map := #PTR (new_section_maps^ [i].map, new_ol.sequence_pointer^);
                module_offset_cv^ [change_count].offset := #OFFSET (old_map);
                module_offset_cv^ [change_count].delta := #OFFSET (new_map) - #OFFSET (old_map);
                change_count := change_count + 1;
              FOREND;
            IFEND;
          IFEND;

        ELSE
          STRINGREP (text, length, old_module_dictionary^ [old_mod_number].kind);
          osp$set_status_abnormal (occ$status_id, oce$invalid_module_kind, text (1, length), status);
          RETURN;
        CASEND;
      IFEND;
    FOREND;

    change_length := change_count - 1;
    compress_change_vector (module_offset_cv, change_length);

    IF change_length > 0 THEN
      module_offset_cv^ [change_length].offset := #SIZE (old_ol.sequence_pointer^);

      RESET predictor.sequence_pointer;
      NEXT predictor_header IN predictor.sequence_pointer;
      RESET predictor.sequence_pointer;
      NEXT fill: [1 .. predictor_header^.size_predictor] IN predictor.sequence_pointer;
      NEXT mod_dictionary_ocv: [1 .. change_length] IN predictor.sequence_pointer;
      FOR i := 1 TO change_length DO
        mod_dictionary_ocv^ [i] := module_offset_cv^ [i];
      FOREND;
      predictor_header^.number_of_mod_ocv_elements := change_length;
      predictor_header^.mod_dictionary_ocv := #REL (mod_dictionary_ocv, predictor.sequence_pointer^);
      predictor_header^.size_predictor := predictor_header^.size_predictor + #SIZE (mod_dictionary_ocv^);
    ELSE
      RESET predictor.sequence_pointer;
      NEXT predictor_header IN predictor.sequence_pointer;
      predictor_header^.number_of_mod_ocv_elements := 0;
    IFEND;
  PROCEND build_mod_dictionary_ocv;

?? EJECT ??
?? OLDTITLE ??
?? NEWTITLE := 'BUILD_MODULE_PREDICTORS' ??
*copyc och$build_module_predictors

  PROCEDURE build_module_predictors
    (    old_file_name: fst$file_reference;
         new_file_name: fst$file_reference;
         old_ol: amt$segment_pointer;
         new_ol: amt$segment_pointer;
         old_module_dictionary: ^llt$module_dictionary;
         new_module_dictionary: ^llt$module_dictionary;
     VAR module_directory: ^oct$module_directory;
     VAR predictor: amt$segment_pointer;
     VAR status: ost$status);

    VAR
      attachment_options: array [1 .. 3] of fst$attachment_option,
      fill: ^SEQ ( * ),
      smp_file_opened: boolean,
      i: llt$module_index,
      j: llt$module_index,
      local_status: ost$status,
      module_predictor: ^SEQ ( * ),
      new_message_header: ^llt$library_member_header,
      new_module_header: ^llt$load_module_header,
      old_message_header: ^llt$library_member_header,
      old_module_header: ^llt$load_module_header,
      predictor_header: ^oct$predictor_header,
      s_predictor: ^SEQ ( * ),
      single_predictor: ^SEQ ( * ),
      single_predictor_size: oct$module_predictor_size,
      smp_fid: amt$file_identifier,
      smp_lfn: ost$name,
      smp_seg: amt$segment_pointer;

?? NEWTITLE := 'abort_handler', EJECT ??

{ PURPOSE:
{   This procedure cleans up when an abort situation occurs
{   within the block structure.
{
{ DESIGN:
{   If the file has been opened, it will be closed before the
{   the procedure returns.
{
{ NOTES:
{
{

    PROCEDURE abort_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        ignore_status: ost$status;

      IF smp_file_opened THEN
        fsp$close_file (smp_fid, ignore_status);
        smp_file_opened := FALSE;
      IFEND;

    PROCEND abort_handler;

?? OLDTITLE, EJECT ??

    status.normal := TRUE;
    smp_file_opened := FALSE;

    pmp$get_unique_name (smp_lfn, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    osp$establish_block_exit_hndlr (^abort_handler);

  /main/
    BEGIN

      attachment_options [1].selector := fsc$access_and_share_modes;
      attachment_options [1].access_modes.selector := fsc$specific_access_modes;
      attachment_options [1].access_modes.value := $fst$file_access_options
            [fsc$read, fsc$shorten, fsc$append, fsc$modify];
      attachment_options [1].share_modes.selector := fsc$determine_from_access_modes;
      attachment_options [2].selector := fsc$create_file;
      attachment_options [2].create_file := TRUE;
      attachment_options [3].selector := fsc$wait_for_attachment;
      attachment_options [3].wait_for_attachment.wait := osc$wait;
      attachment_options [3].wait_for_attachment.wait_time := fsc$longest_wait_time;

      smp_file_opened := TRUE;
      fsp$open_file (smp_lfn, amc$segment, ^attachment_options, NIL, NIL, NIL, NIL, smp_fid, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      amp$get_segment_pointer (smp_fid, amc$sequence_pointer, smp_seg, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      single_predictor := smp_seg.sequence_pointer;
      RESET predictor.sequence_pointer;
      NEXT predictor_header IN predictor.sequence_pointer;
      predictor_header^.number_module_predictors := 0;
      single_predictor_size := 0;

      FOR i := 1 TO UPPERBOUND (module_directory^) DO
        j := module_directory^ [i].new_module_number;
        IF (j <> 0) THEN
          CASE old_module_dictionary^ [i].kind OF
          = llc$load_module =
            old_module_header := #PTR (old_module_dictionary^ [i].
                  module_header, old_ol.sequence_pointer^);
            new_module_header := #PTR (new_module_dictionary^ [j].
                  module_header, new_ol.sequence_pointer^);
            build_load_module_predictor (old_module_header, new_module_header,
                  old_module_dictionary^ [i].name, old_file_name, new_file_name, old_ol, new_ol,
                  single_predictor, single_predictor_size,
                  module_directory^ [i], status);
            IF NOT status.normal THEN
              EXIT /main/;
            IFEND;
          = llc$message_module =
            old_message_header := #PTR (old_module_dictionary^ [i].
                  message_header, old_ol.sequence_pointer^);
            new_message_header := #PTR (new_module_dictionary^ [j].
                  message_header, new_ol.sequence_pointer^);
            build_message_predictor (old_message_header, new_message_header,
                  old_module_dictionary^ [i].name, old_ol, new_ol,
                  single_predictor, single_predictor_size, status);
            IF NOT status.normal THEN
              EXIT /main/;
            IFEND;
          ELSE
            ;
          CASEND;
          IF single_predictor_size > 0 THEN
            RESET single_predictor;
            RESET predictor.sequence_pointer;
            NEXT fill: [[REP predictor_header^.size_predictor OF cell]] IN
                  predictor.sequence_pointer;
            NEXT module_predictor: [[REP single_predictor_size OF cell]] IN
                  predictor.sequence_pointer;
            NEXT s_predictor: [[REP single_predictor_size OF cell]] IN
                  single_predictor;
            module_predictor^ := s_predictor^;
            predictor_header^.number_module_predictors :=
                  predictor_header^.number_module_predictors + 1;
            predictor_header^.size_predictor :=
                  predictor_header^.size_predictor + single_predictor_size;
          IFEND;
          single_predictor_size := 0;
        IFEND;
      FOREND;

    END /main/;

    IF smp_file_opened THEN
      fsp$close_file (smp_fid, local_status);
      smp_file_opened := FALSE;
      IF status.normal AND (NOT local_status.normal) THEN
        status := local_status;
      IFEND;
    IFEND;

    osp$disestablish_cond_handler;

  PROCEND build_module_predictors;

?? EJECT ??
?? OLDTITLE ??
?? NEWTITLE := 'BUILD_NORMAL_OFFSET_CV' ??
*copyc och$build_normal_offset_cv

  PROCEDURE build_normal_offset_cv
    (    old_module_header: ^llt$load_module_header;
         new_module_header: ^llt$load_module_header;
         old_file_name: fst$file_reference;
         new_file_name: fst$file_reference;
         old_ol: amt$segment_pointer;
         new_ol: amt$segment_pointer;
     VAR normal_socv: amt$segment_pointer;
     VAR section_directory: ^oct$section_directory;
     VAR number_section_offset_cvs: llt$section_ordinal;
     VAR status: ost$status);

    VAR
      i: llt$section_ordinal,
      j: llt$section_ordinal,
      new_component_info: ^llt$component_information,
      new_info_element_header: ^llt$info_element_header,
      new_information_element: llt$info_element_header,
      new_section_map: ^llt$section_map_items,
      new_section_maps: ^llt$section_maps,
      old_component_info: ^llt$component_information,
      old_info_element_header: ^llt$info_element_header,
      old_information_element: llt$info_element_header,
      old_section_definitions: ^llt$object_text_descriptor,
      old_section_map: ^llt$section_map_items,
      old_section_maps: ^llt$section_maps,
      socv_generated: boolean,
      section_offset_cv: ^oct$section_offset_changes;

    status.normal := TRUE;

    number_section_offset_cvs := 0;
    RESET normal_socv.sequence_pointer;
    IF (llc$information_element IN old_module_header^.elements_defined) AND
          (llc$information_element IN new_module_header^.elements_defined) THEN

      old_info_element_header := #PTR (old_module_header^.information_element, old_ol.sequence_pointer^);
      new_info_element_header := #PTR (new_module_header^.information_element, new_ol.sequence_pointer^);

      IF (old_info_element_header^.version = llc$info_element_version) THEN
        old_information_element := old_info_element_header^;
      ELSE
        ocp$convert_information_element (old_info_element_header, old_information_element);
      IFEND;

      IF (old_information_element.number_of_section_maps = 0) THEN
        osp$set_status_abnormal (occ$status_id, oce$no_section_maps, old_file_name, status);
        RETURN;
      IFEND;

      IF (new_info_element_header^.version = llc$info_element_version) THEN
        new_information_element := new_info_element_header^;
      ELSE
        ocp$convert_information_element (new_info_element_header, new_information_element);
      IFEND;

      IF (new_information_element.number_of_section_maps = 0) THEN
        osp$set_status_abnormal (occ$status_id, oce$no_section_maps, old_file_name, status);
        RETURN;
      IFEND;

      old_section_maps := #PTR (old_information_element.section_maps, old_ol.sequence_pointer^);
      new_section_maps := #PTR (new_information_element.section_maps, new_ol.sequence_pointer^);
      IF old_information_element.number_of_components > 0 THEN
        old_component_info := #PTR (old_information_element.component_ptr, old_ol.sequence_pointer^);
      ELSE
        old_component_info := NIL;
      IFEND;
      IF new_information_element.number_of_components > 0 THEN
        new_component_info := #PTR (new_information_element.component_ptr, new_ol.sequence_pointer^);
      ELSE
        new_component_info := NIL;
      IFEND;

      IF llc$section_element IN old_module_header^.interpretive_header.elements_defined THEN
        old_section_definitions := #PTR (old_module_header^.interpretive_header.section_definitions,
              old_ol.sequence_pointer^);
      ELSE
        old_section_definitions := NIL;
      IFEND;
      FOR i := 0 TO UPPERBOUND (section_directory^) DO
        IF (section_directory^ [i].new_section_number <> occ$invalid_section_ordinal) AND
              (old_section_maps^ [i].number_of_items > 0) THEN
          j := section_directory^ [i].new_section_number;
          old_section_map := #PTR (old_section_maps^ [i].map, old_ol.sequence_pointer^);
          new_section_map := #PTR (new_section_maps^ [j].map, new_ol.sequence_pointer^);
          build_section_ocv (old_section_map, new_section_map, i, old_section_definitions,
                old_ol.sequence_pointer, old_component_info, new_component_info, normal_socv,
                section_offset_cv, socv_generated, status);
          IF NOT status.normal THEN
            RETURN;
          IFEND;
          IF socv_generated THEN
            number_section_offset_cvs := number_section_offset_cvs + 1;
            section_directory^ [i].section_offset_change_vector := ^section_offset_cv^.change_list;
          IFEND;
        IFEND;
      FOREND;
    IFEND;
  PROCEND build_normal_offset_cv;
?? EJECT ??
?? OLDTITLE ??
?? NEWTITLE := 'BUILD_OL_DICTIONARY_OCV' ??
*copyc och$build_ol_dictionary_ocv

  PROCEDURE build_ol_dictionary_ocv
    (    p_old_ol: amt$segment_pointer;
         p_new_ol: amt$segment_pointer;
     VAR predictor: amt$segment_pointer;
     VAR status: ost$status);

    VAR
      change_length: oct$max_offset_changes,
      i: 0 .. llc$max_dictionaries_on_library,
      j: 0 .. llc$max_dictionaries_on_library,
      k: oct$max_offset_changes,
      match_found: boolean,
      new_command_dictionary: ^llt$command_dictionary,
      new_ept_dictionary: ^llt$entry_point_dictionary,
      new_function_dictionary: ^llt$function_dictionary,
      new_header: ^llt$object_library_header,
      new_help_dictionary: ^llt$help_module_dictionary,
      new_message_dictionary: ^llt$message_module_dictionary,
      new_module_dictionary: ^llt$module_dictionary,
      new_ol: amt$segment_pointer,
      new_ol_dictionaries: ^llt$object_library_dictionaries,
      new_panel_dictionary: ^llt$panel_dictionary,
      ol_dictionary_changes: ^oct$offset_change_list,
      ol_dictionary_ocv: ^oct$offset_change_list,
      old_command_dictionary: ^llt$command_dictionary,
      old_ept_dictionary: ^llt$entry_point_dictionary,
      old_function_dictionary: ^llt$function_dictionary,
      old_header: ^llt$object_library_header,
      old_help_dictionary: ^llt$help_module_dictionary,
      old_message_dictionary: ^llt$message_module_dictionary,
      old_module_dictionary: ^llt$module_dictionary,
      old_ol: amt$segment_pointer,
      old_ol_dictionaries: ^llt$object_library_dictionaries,
      old_panel_dictionary: ^llt$panel_dictionary,
      predictor_fill: ^oct$fill_sequence,
      predictor_header: ^oct$predictor_header,
      search_complete: boolean,
      start: 0 .. llc$max_dictionaries_on_library;

    status.normal := TRUE;

    new_ol := p_new_ol;
    old_ol := p_old_ol;

    RESET old_ol.sequence_pointer;
    RESET new_ol.sequence_pointer;
    RESET predictor.sequence_pointer;
    NEXT predictor_header IN predictor.sequence_pointer;
    RESET predictor.sequence_pointer;
    NEXT predictor_fill: [1 .. predictor_header^.size_predictor] IN predictor.sequence_pointer;
    NEXT old_header IN old_ol.sequence_pointer;
    NEXT new_header IN new_ol.sequence_pointer;
    NEXT old_ol_dictionaries: [1 .. old_header^.number_of_dictionaries] IN old_ol.sequence_pointer;
    NEXT new_ol_dictionaries: [1 .. new_header^.number_of_dictionaries] IN new_ol.sequence_pointer;
    k := 1;
    PUSH ol_dictionary_changes: [1 .. old_header^.number_of_dictionaries];
    start := 1;
    FOR i := 1 TO old_header^.number_of_dictionaries DO
      match_found := FALSE;
      search_complete := FALSE;
      j := start;
      WHILE NOT match_found AND NOT search_complete DO
        match_found := (old_ol_dictionaries^ [i].kind = new_ol_dictionaries^ [j].kind);
        IF match_found THEN
          CASE old_ol_dictionaries^ [i].kind OF
          = llc$module_dictionary =
            old_module_dictionary := #PTR (old_ol_dictionaries^ [i].module_dictionary,
                  old_ol.sequence_pointer^);
            new_module_dictionary := #PTR (new_ol_dictionaries^ [j].module_dictionary,
                  new_ol.sequence_pointer^);
            ol_dictionary_changes^ [k].offset := #OFFSET (old_module_dictionary);
            ol_dictionary_changes^ [k].delta := #OFFSET (new_module_dictionary) -
                  #OFFSET (old_module_dictionary);
            k := k + 1;
          = llc$entry_point_dictionary =
            old_ept_dictionary := #PTR (old_ol_dictionaries^ [i].entry_point_dictionary,
                  old_ol.sequence_pointer^);
            new_ept_dictionary := #PTR (new_ol_dictionaries^ [j].entry_point_dictionary,
                  new_ol.sequence_pointer^);
            ol_dictionary_changes^ [k].offset := #OFFSET (old_ept_dictionary);
            ol_dictionary_changes^ [k].delta := #OFFSET (new_ept_dictionary) - #OFFSET (old_ept_dictionary);
            k := k + 1;
          = llc$command_dictionary =
            old_command_dictionary := #PTR (old_ol_dictionaries^ [i].command_dictionary,
                  old_ol.sequence_pointer^);
            new_command_dictionary := #PTR (new_ol_dictionaries^ [j].command_dictionary,
                  new_ol.sequence_pointer^);
            ol_dictionary_changes^ [k].offset := #OFFSET (old_command_dictionary);
            ol_dictionary_changes^ [k].delta := #OFFSET (new_command_dictionary) -
                  #OFFSET (old_command_dictionary);
            k := k + 1;
          = llc$function_dictionary =
            old_function_dictionary := #PTR (old_ol_dictionaries^ [i].function_dictionary,
                  old_ol.sequence_pointer^);
            new_function_dictionary := #PTR (new_ol_dictionaries^ [j].function_dictionary,
                  new_ol.sequence_pointer^);
            ol_dictionary_changes^ [k].offset := #OFFSET (old_function_dictionary);
            ol_dictionary_changes^ [k].delta := #OFFSET (new_function_dictionary) -
                  #OFFSET (old_function_dictionary);
            k := k + 1;
          = llc$help_module_dictionary =
            old_help_dictionary := #PTR (old_ol_dictionaries^ [i].help_module_dictionary,
                  old_ol.sequence_pointer^);
            new_help_dictionary := #PTR (new_ol_dictionaries^ [j].help_module_dictionary,
                  new_ol.sequence_pointer^);
            ol_dictionary_changes^ [k].offset := #OFFSET (old_help_dictionary);
            ol_dictionary_changes^ [k].delta := #OFFSET (new_help_dictionary) - #OFFSET (old_help_dictionary);
            k := k + 1;
          = llc$message_module_dictionary =
            old_message_dictionary := #PTR (old_ol_dictionaries^ [i].message_module_dictionary,
                  old_ol.sequence_pointer^);
            new_message_dictionary := #PTR (new_ol_dictionaries^ [j].message_module_dictionary,
                  new_ol.sequence_pointer^);
            ol_dictionary_changes^ [k].offset := #OFFSET (old_message_dictionary);
            ol_dictionary_changes^ [k].delta := #OFFSET (new_message_dictionary) -
                  #OFFSET (old_message_dictionary);
            k := k + 1;
          = llc$panel_dictionary =
            old_panel_dictionary := #PTR (old_ol_dictionaries^ [i].panel_dictionary,
                  old_ol.sequence_pointer^);
            new_panel_dictionary := #PTR (new_ol_dictionaries^ [j].panel_dictionary,
                  new_ol.sequence_pointer^);
            ol_dictionary_changes^ [k].offset := #OFFSET (old_panel_dictionary);
            ol_dictionary_changes^ [k].delta := #OFFSET (new_panel_dictionary) -
                  #OFFSET (old_panel_dictionary);
            k := k + 1;
          ELSE
            ;
          CASEND;

          start := start + 1;
          IF start > new_header^.number_of_dictionaries THEN
            start := 1;
          IFEND;
        ELSE
          j := j + 1;
          IF j > new_header^.number_of_dictionaries THEN
            j := 1;
          IFEND;
          search_complete := (j = start);
        IFEND;
      WHILEND;
    FOREND;

    change_length := k - 1;
    compress_change_vector (ol_dictionary_changes, change_length);

    IF change_length > 0 THEN
      NEXT ol_dictionary_ocv: [1 .. change_length] IN predictor.sequence_pointer;
      FOR i := 1 TO change_length DO
        ol_dictionary_ocv^ [i] := ol_dictionary_changes^ [i];
      FOREND;
      predictor_header^.number_of_ol_ocv_elements := change_length;
      predictor_header^.ol_dictionary_ocv := #REL (ol_dictionary_ocv, predictor.sequence_pointer^);
      predictor_header^.size_predictor := predictor_header^.size_predictor + #SIZE (ol_dictionary_ocv^);
    ELSE
      predictor_header^.number_of_ol_ocv_elements := 0;
    IFEND;
  PROCEND build_ol_dictionary_ocv;
?? EJECT ??
?? OLDTITLE ??
?? NEWTITLE := 'BUILD_SECTION_NUMBER_CV' ??
*copyc och$build_section_number_cv

  PROCEDURE build_section_number_cv
    (    old_module_header: ^llt$load_module_header;
         new_module_header: ^llt$load_module_header;
         p_old_ol: amt$segment_pointer;
         p_new_ol: amt$segment_pointer;
     VAR section_number_cv: ^oct$new_ordinal_list;
     VAR module_is_bound: boolean;
     VAR section_directory: ^oct$section_directory;
     VAR status: ost$status);

    VAR
      i: llt$section_ordinal,
      j: llt$section_ordinal,
      match_found: boolean,
      new_identification_record: ^llt$identification,
      new_interpretive_element: ^llt$object_text_descriptor,
      new_ol: amt$segment_pointer,
      new_section_list: ^oct$section_list,
      object_text_descriptor: ^llt$object_text_descriptor,
      old_identification_record: ^llt$identification,
      old_info_element: ^llt$info_element_header,
      old_information_element: llt$info_element_header,
      old_interpretive_element: ^llt$object_text_descriptor,
      old_ol: amt$segment_pointer,
      old_section_list: ^oct$section_list,
      same_section_lists: boolean,
      search_complete: boolean,
      section_definitions: ^llt$object_text_descriptor,
      start: llt$section_ordinal;

    status.normal := TRUE;

    new_ol := p_new_ol;
    old_ol := p_old_ol;

    module_is_bound := FALSE;
    IF llc$information_element IN old_module_header^.elements_defined THEN
      old_info_element := #PTR (old_module_header^.information_element, old_ol.sequence_pointer^);
      IF old_info_element^.version = llc$info_element_version THEN
        old_information_element := old_info_element^;
      ELSE
        ocp$convert_information_element (old_info_element, old_information_element);
      IFEND;

      module_is_bound := (old_information_element.number_of_components > 0);
    IFEND;

    IF (llc$interpretive_element IN old_module_header^.elements_defined) AND
          (llc$interpretive_element IN new_module_header^.elements_defined) THEN
      old_interpretive_element := #PTR (old_module_header^.interpretive_element, old_ol.sequence_pointer^);
      new_interpretive_element := #PTR (new_module_header^.interpretive_element, new_ol.sequence_pointer^);

      RESET old_ol.sequence_pointer TO old_interpretive_element;
      NEXT object_text_descriptor IN old_ol.sequence_pointer;
      IF object_text_descriptor^.kind <> llc$identification THEN
        osp$set_status_abnormal (occ$status_id, oce$id_record_expected, ' ', status);
        RETURN;
      IFEND;

      NEXT old_identification_record IN old_ol.sequence_pointer;

      IF NOT (llc$section_element IN old_module_header^.interpretive_header.elements_defined) THEN
        RETURN;
      IFEND;

      section_definitions := #PTR (old_module_header^.interpretive_header.section_definitions,
            old_ol.sequence_pointer^);
      PUSH old_section_list: [0 .. old_identification_record^.greatest_section_ordinal];
      create_section_list (section_definitions, old_ol, old_section_list, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      RESET new_ol.sequence_pointer TO new_interpretive_element;
      NEXT object_text_descriptor IN new_ol.sequence_pointer;
      IF object_text_descriptor^.kind <> llc$identification THEN
        osp$set_status_abnormal (occ$status_id, oce$id_record_expected, ' ', status);
        RETURN;
      IFEND;

      NEXT new_identification_record IN new_ol.sequence_pointer;

      IF NOT (llc$section_element IN new_module_header^.interpretive_header.elements_defined) THEN
        RETURN;
      IFEND;

      section_definitions := #PTR (new_module_header^.interpretive_header.section_definitions,
            new_ol.sequence_pointer^);
      PUSH new_section_list: [0 .. new_identification_record^.greatest_section_ordinal];
      create_section_list (section_definitions, new_ol, new_section_list, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      IF new_identification_record^.greatest_section_ordinal =
            old_identification_record^.greatest_section_ordinal THEN
        i := 0;
        same_section_lists := TRUE;
        WHILE same_section_lists AND (i <= old_identification_record^.greatest_section_ordinal) DO
          same_section_lists := (old_section_list^ [i] = new_section_list^ [i]);
          i := i + 1;
        WHILEND;
      ELSE
        same_section_lists := FALSE;
      IFEND;

      ALLOCATE section_directory: [0 .. old_identification_record^.greatest_section_ordinal];
      IF same_section_lists THEN
        FOR i := 0 TO UPPERBOUND (section_directory^) DO
          section_directory^ [i].new_section_number := i;
        FOREND;
        RETURN;
      IFEND;

      ALLOCATE section_number_cv: [0 .. old_identification_record^.greatest_section_ordinal];

      start := 0;
      FOR i := 0 TO old_identification_record^.greatest_section_ordinal DO
        j := start;
        match_found := FALSE;
        search_complete := FALSE;
        section_number_cv^ [i] := occ$invalid_section_ordinal;
        section_directory^ [i].new_section_number := occ$invalid_section_ordinal;

        WHILE NOT match_found AND NOT search_complete DO
          match_found := (old_section_list^ [i] = new_section_list^ [j]) AND (old_section_list^ [i].
                found = FALSE);
          IF match_found THEN
            old_section_list^ [i].found := TRUE;
            new_section_list^ [j].found := TRUE;
            section_number_cv^ [i] := j;
            section_directory^ [i].new_section_number := j;
            start := j + 1;
            IF start > new_identification_record^.greatest_section_ordinal THEN
              start := 0;
            IFEND;
          ELSE
            j := j + 1;
            IF j > new_identification_record^.greatest_section_ordinal THEN
              j := 0;
            IFEND;
            search_complete := (j = start);
          IFEND;
        WHILEND;
      FOREND;
    IFEND;
  PROCEND build_section_number_cv;
?? EJECT ??
?? OLDTITLE ??
?? NEWTITLE := 'BUILD_SECTION_OCV' ??
*copyc och$build_section_ocv

  PROCEDURE build_section_ocv
    (    old_section_map: ^llt$section_map_items;
         new_section_map: ^llt$section_map_items;
         section_ordinal: llt$section_ordinal;
         old_section_definitions: ^llt$object_text_descriptor;
         p_old_object_library: ^SEQ ( * );
         old_component_info: ^llt$component_information;
         new_component_info: ^llt$component_information;
     VAR normal_socv: amt$segment_pointer;
     VAR section_offset_cv: ^oct$section_offset_changes;
     VAR socv_generated: boolean;
     VAR status: ost$status);

    VAR
      i: llt$section_ordinal,
      j: llt$section_ordinal,
      k: llt$section_ordinal,
      length: llt$section_ordinal,
      match_found: boolean,
      object_text_descriptor: ^llt$object_text_descriptor,
      old_object_library: ^SEQ ( * ),
      search_complete: boolean,
      section_definition: ^llt$section_definition,
      section_found: boolean,
      section_offset_changes: ^oct$offset_change_list,
      start: llt$section_ordinal,
      string_length: integer,
      string_ordinal: string (osc$max_string_size);

    status.normal := TRUE;

    old_object_library := p_old_object_library;

    PUSH section_offset_changes: [1 .. llc$max_section_ordinal];
    k := 1;
    start := 1;
    FOR i := 1 TO UPPERBOUND (old_section_map^) DO
      j := start;
      match_found := FALSE;
      search_complete := FALSE;
      WHILE NOT match_found AND NOT search_complete DO
        match_found := (old_section_map^ [i].name = new_section_map^ [j].name) AND
              (old_component_info^ [old_section_map^ [i].component].
              name = new_component_info^ [new_section_map^ [j].component].name);
        IF match_found THEN
          section_offset_changes^ [k].offset := old_section_map^ [i].offset;
          section_offset_changes^ [k].delta := new_section_map^ [j].offset - old_section_map^ [i].offset;
          k := k + 1;
          start := j + 1;
          IF start > UPPERBOUND (new_section_map^) THEN
            start := 1;
          IFEND;
        ELSE
          j := j + 1;
          IF j > UPPERBOUND (new_section_map^) THEN
            j := 1;
          IFEND;
          search_complete := (j = start);
        IFEND;
      WHILEND;
    FOREND;
    length := k - 1;
    i := 1;
    WHILE (i <= length) AND (section_offset_changes^ [i].delta = 0) DO
      i := i + 1;
    WHILEND;
    IF ((i - 1) = length) OR (length = 0) THEN
      socv_generated := FALSE;
      RETURN;
    IFEND;
    socv_generated := TRUE;

{ Compress section offset change vector.

    i := 2;
    j := 2;
    WHILE i <= length DO
      WHILE (i <= length) AND (section_offset_changes^ [i - 1].delta = section_offset_changes^ [i].delta) DO
        i := i + 1;
      WHILEND;
      IF i <= length THEN
        section_offset_changes^ [j] := section_offset_changes^ [i];
        j := j + 1;
        i := i + 1;
      IFEND;
    WHILEND;
    length := j - 1;
    RESET old_object_library TO old_section_definitions;
    section_found := FALSE;
    REPEAT
      NEXT object_text_descriptor IN old_object_library;
      CASE object_text_descriptor^.kind OF
      = llc$section_definition, llc$allotted_section_definition, llc$unallocated_common_block =
        NEXT section_definition IN old_object_library;
        section_found := (section_definition^.section_ordinal = section_ordinal);
      ELSE
        STRINGREP (string_ordinal, string_length, section_ordinal);
        osp$set_status_abnormal (occ$status_id, oce$no_section_definition, string_ordinal (1, string_length),
              status);
        RETURN;
      CASEND;
    UNTIL section_found;
    NEXT section_offset_cv: [1 .. length] IN normal_socv.sequence_pointer;
    section_offset_cv^.header.section_ordinal := section_ordinal;
    section_offset_cv^.header.number_of_socv_items := length;
    section_offset_cv^.header.section_kind := section_definition^.kind;
    section_offset_cv^.change_list := section_offset_changes^;
  PROCEND build_section_ocv;
?? EJECT ??
?? OLDTITLE ??
?? NEWTITLE := 'COMPRESS_CHANGE_VECTOR' ??
*copyc och$compress_change_vector

  PROCEDURE compress_change_vector
    (VAR change_vector: ^oct$offset_change_list;
     VAR number: oct$max_offset_changes);

    PROCEDURE sort_change_vector
      (    number: oct$max_offset_changes;
       VAR change_vector: ^oct$offset_change_list);

      VAR
        i: integer,
        j: integer,
        key: llt$section_offset,
        left: integer,
        right: integer,
        temp: oct$change_items;


      IF number = 2 THEN
        IF change_vector^ [1].offset > change_vector^ [2].offset THEN
          temp := change_vector^ [1];
          change_vector^ [1] := change_vector^ [2];
          change_vector^ [2] := temp;
        IFEND;
        RETURN;
      IFEND;

      left := (number DIV 2) + 1;
      right := number;

    /outer_loop/
      WHILE TRUE DO
        IF left > 1 THEN
          left := left - 1;
          temp := change_vector^ [left];
          key := change_vector^ [left].offset;
        ELSE
          temp := change_vector^ [right];
          key := change_vector^ [right].offset;
          change_vector^ [right] := change_vector^ [1];
          right := right - 1;
          IF right = 1 THEN
            change_vector^ [right] := temp;
            RETURN;
          IFEND;
        IFEND;

        j := left;

      /inner_loop/
        WHILE TRUE DO
          i := j;
          j := j + j;
          IF j < right THEN
            IF (change_vector^ [j].offset < change_vector^ [j + 1].offset) THEN
              j := j + 1;
            IFEND;
          ELSEIF j > right THEN
            EXIT /inner_loop/;
          IFEND;

          IF key >= change_vector^ [j].offset THEN
            EXIT /inner_loop/;
          IFEND;

          change_vector^ [i] := change_vector^ [j];
        WHILEND /inner_loop/;

        change_vector^ [i] := temp;
      WHILEND /outer_loop/;
    PROCEND sort_change_vector;

    VAR
      i: integer,
      j: integer;

    IF number <= 1 THEN
      RETURN;
    IFEND;

    sort_change_vector (number, change_vector);

    j := 1;
    i := 1;
    WHILE i <= number DO
      WHILE (i < number) AND (change_vector^ [i].delta = change_vector^ [i + 1].delta) DO
        i := i + 1;
      WHILEND;
      change_vector^ [j] := change_vector^ [i];
      j := j + 1;
      i := i + 1;
    WHILEND;

    number := j - 1;
  PROCEND compress_change_vector;
?? EJECT ??
?? OLDTITLE ??
?? NEWTITLE := 'CONSTRUCT_MODULE_PREDICTOR' ??
*copyc och$construct_module_predictor

  PROCEDURE construct_module_predictor
    (    module_name: pmt$program_name;
         number_section_offset_cvs: llt$section_ordinal;
         section_number_cv: ^oct$new_ordinal_list;
         p_normal_socv: amt$segment_pointer;
         binding_section_ocv: ^oct$offset_change_list;
         binding_section: llt$section_ordinal;
         component_index_cv: ^array [1 .. * ] of 0 .. llc$max_components;
         length_component_index_cv: 0 .. llc$max_components;
     VAR single_predictor: ^SEQ ( * );
     VAR size_of_predictor: oct$module_predictor_size);

    VAR
      binding_section_changes: ^oct$offset_change_list,
      component_index_changes: ^array [1 .. * ] of 0 .. llc$max_components,
      i: llt$section_length,
      module_predictor_header: ^oct$single_module_predictor_hdr,
      normal_socv: amt$segment_pointer,
      section_info: ^oct$section_info,
      section_number_change_list: ^oct$new_ordinal_list,
      section_offset_change_list: ^oct$offset_change_list,
      section_offset_cv: ^oct$section_offset_changes;

    normal_socv := p_normal_socv;

    RESET single_predictor;
    NEXT module_predictor_header IN single_predictor;
    size_of_predictor := #SIZE (module_predictor_header^);
    module_predictor_header^.module_name := module_name;
    module_predictor_header^.kind := llc$load_module;
    module_predictor_header^.last_section_ordinal := occ$invalid_section_ordinal;
    module_predictor_header^.length_normal_section_ocv := 0;
    module_predictor_header^.length_binding_socv := 0;
    module_predictor_header^.length_component_index_cv := 0;
    IF section_number_cv <> NIL THEN
      module_predictor_header^.last_section_ordinal := UPPERBOUND (section_number_cv^);
      NEXT section_number_change_list: [0 .. UPPERBOUND (section_number_cv^)] IN single_predictor;
      section_number_change_list^ := section_number_cv^;
      module_predictor_header^.section_number_cv := #REL (section_number_change_list, single_predictor^);
      size_of_predictor := size_of_predictor + #SIZE (section_number_change_list^);
    IFEND;
    IF number_section_offset_cvs > 0 THEN
      module_predictor_header^.length_normal_section_ocv := number_section_offset_cvs;
      RESET normal_socv.sequence_pointer;
      NEXT section_info IN normal_socv.sequence_pointer;
      NEXT section_offset_change_list: [1 .. section_info^.number_of_socv_items] IN
            normal_socv.sequence_pointer;
      NEXT section_offset_cv: [1 .. section_info^.number_of_socv_items] IN single_predictor;
      module_predictor_header^.section_offset_cv := #REL (section_offset_cv, single_predictor^);
      section_offset_cv^.header := section_info^;
      section_offset_cv^.change_list := section_offset_change_list^;
      size_of_predictor := size_of_predictor + #SIZE (section_offset_cv^);
      FOR i := 2 TO number_section_offset_cvs DO
        NEXT section_info IN normal_socv.sequence_pointer;
        NEXT section_offset_change_list: [1 .. section_info^.number_of_socv_items] IN
              normal_socv.sequence_pointer;
        NEXT section_offset_cv: [1 .. section_info^.number_of_socv_items] IN single_predictor;
        section_offset_cv^.header := section_info^;
        section_offset_cv^.change_list := section_offset_change_list^;
        size_of_predictor := size_of_predictor + #SIZE (section_offset_cv^);
      FOREND;
    IFEND;
    IF binding_section_ocv <> NIL THEN
      module_predictor_header^.length_binding_socv := UPPERBOUND (binding_section_ocv^);
      NEXT binding_section_changes: [1 .. UPPERBOUND (binding_section_ocv^)] IN single_predictor;
      binding_section_changes^ := binding_section_ocv^;
      size_of_predictor := size_of_predictor + #SIZE (binding_section_changes^);
      module_predictor_header^.binding_section_ocv := #REL (binding_section_changes, single_predictor^);
      module_predictor_header^.binding_section_ordinal := binding_section;
    IFEND;
    IF component_index_cv <> NIL THEN
      module_predictor_header^.length_component_index_cv := length_component_index_cv;
      NEXT component_index_changes: [1 .. length_component_index_cv] IN single_predictor;
      component_index_changes^ := component_index_cv^;
      size_of_predictor := size_of_predictor + #SIZE (component_index_changes^);
      module_predictor_header^.component_index_cv := #REL (component_index_changes, single_predictor^);
    IFEND;

    module_predictor_header^.predictor_size := size_of_predictor;
    IF (module_predictor_header^.last_section_ordinal = occ$invalid_section_ordinal) AND
          (module_predictor_header^.length_normal_section_ocv = 0) AND
          (module_predictor_header^.length_binding_socv = 0) AND
          (module_predictor_header^.length_component_index_cv = 0) THEN
      size_of_predictor := 0;
    IFEND;
  PROCEND construct_module_predictor;
?? EJECT ??
?? OLDTITLE ??
?? NEWTITLE := 'CREATE_SECTION_LIST' ??
*copyc och$create_section_list

  PROCEDURE create_section_list
    (    section_definitions: ^llt$object_text_descriptor;
         p_seg_p: amt$segment_pointer;
     VAR section_list: ^oct$section_list;
     VAR status: ost$status);

    VAR
      i: llt$section_ordinal,
      length: integer,
      no_more_sections: boolean,
      object_text_descriptor: ^llt$object_text_descriptor,
      obsolete_segment_definition: ^llt$obsolete_segment_definition,
      section_definition: ^llt$section_definition,
      seg_p: amt$segment_pointer,
      segment_definition: ^llt$segment_definition,
      text: string (osc$max_string_size);

    status.normal := TRUE;

    seg_p := p_seg_p;

    FOR i := 0 TO UPPERBOUND (section_list^) DO
      no_more_sections := FALSE;
      RESET seg_p.sequence_pointer TO section_definitions;
      REPEAT
        NEXT object_text_descriptor IN seg_p.sequence_pointer;
        CASE object_text_descriptor^.kind OF
        = llc$section_definition, llc$allotted_section_definition, llc$unallocated_common_block =
          NEXT section_definition IN seg_p.sequence_pointer;
        = llc$segment_definition, llc$allotted_segment_definition =
          NEXT segment_definition IN seg_p.sequence_pointer;
          section_definition := ^segment_definition^.section_definition;
        = llc$obsolete_segment_definition, llc$obsolete_allotted_seg_def =
          NEXT obsolete_segment_definition IN seg_p.sequence_pointer;
          section_definition := ^obsolete_segment_definition^.section_definition;
        ELSE
          no_more_sections := TRUE;
        CASEND;
      UNTIL no_more_sections OR (section_definition^.section_ordinal = i);
      IF section_definition^.section_ordinal = i THEN
        section_list^ [i].found := FALSE;
        section_list^ [i].allotted := (object_text_descriptor^.kind = llc$allotted_section_definition) OR
              (object_text_descriptor^.kind = llc$allotted_segment_definition) OR
              (object_text_descriptor^.kind = llc$obsolete_allotted_seg_def);
        section_list^ [i].kind := section_definition^.kind;
        section_list^ [i].access_attributes := section_definition^.access_attributes;
        section_list^ [i].name := section_definition^.name;
      ELSE
        STRINGREP (text, length, i);
        osp$set_status_abnormal (occ$status_id, oce$no_section_definition, text (1, length), status);
        RETURN;
      IFEND;
    FOREND;
  PROCEND create_section_list;
?? EJECT ??
?? OLDTITLE ??
*copyc och$generate_ol_predictor

  PROCEDURE [XDCL] ocp$generate_ol_predictor
    (    old_file_name: fst$file_reference;
         new_file_name: fst$file_reference;
     VAR old_ol: amt$segment_pointer;
     VAR new_ol: amt$segment_pointer;
     VAR predictor: amt$segment_pointer;
     VAR module_directory: ^oct$module_directory;
     VAR status: ost$status);

    VAR
      i: llt$module_index,
      j: llt$module_index,
      match_found: boolean,
      new_found: boolean,
      new_header: ^llt$object_library_header,
      new_module_dictionary: ^llt$module_dictionary,
      new_ol_dictionaries: ^llt$object_library_dictionaries,
      old_found: boolean,
      old_header: ^llt$object_library_header,
      old_module_dictionary: ^llt$module_dictionary,
      old_ol_dictionaries: ^llt$object_library_dictionaries,
      predictor_header: ^oct$predictor_header,
      search_complete: boolean,
      start: llt$module_index;

    status.normal := TRUE;

    RESET predictor.sequence_pointer;
    NEXT predictor_header IN predictor.sequence_pointer;
    predictor_header^.size_predictor := #SIZE (predictor_header^);

    RESET old_ol.sequence_pointer;
    RESET new_ol.sequence_pointer;

    NEXT old_header IN old_ol.sequence_pointer;
    IF old_header^.version <> llc$object_library_version THEN
      osp$set_status_abnormal (occ$status_id, oce$invalid_library_version, old_file_name, status);
      RETURN;
    IFEND;

    NEXT new_header IN new_ol.sequence_pointer;
    IF new_header^.version <> llc$object_library_version THEN
      osp$set_status_abnormal (occ$status_id, oce$invalid_library_version, new_file_name, status);
      RETURN;
    IFEND;

    NEXT old_ol_dictionaries: [1 .. old_header^.number_of_dictionaries] IN old_ol.sequence_pointer;
    NEXT new_ol_dictionaries: [1 .. new_header^.number_of_dictionaries] IN new_ol.sequence_pointer;

    i := 1;
    old_found := FALSE;
    WHILE NOT old_found AND (i <= old_header^.number_of_dictionaries) DO
      IF old_ol_dictionaries^ [i].kind = llc$module_dictionary THEN
        old_found := TRUE;
        old_module_dictionary := #PTR (old_ol_dictionaries^ [i].module_dictionary, old_ol.sequence_pointer^);
      ELSE
        i := i + 1;
      IFEND;
    WHILEND;
    IF old_found THEN
      i := 1;
      new_found := FALSE;
      WHILE NOT new_found AND (i <= new_header^.number_of_dictionaries) DO
        IF new_ol_dictionaries^ [i].kind = llc$module_dictionary THEN
          new_found := TRUE;
          new_module_dictionary := #PTR (new_ol_dictionaries^ [i].module_dictionary,
                new_ol.sequence_pointer^);
        ELSE
          i := i + 1;
        IFEND;
      WHILEND;
      IF new_found THEN
        ALLOCATE module_directory: [1 .. UPPERBOUND (old_module_dictionary^)];
        start := 1;
        FOR i := 1 TO UPPERBOUND (old_module_dictionary^) DO
          match_found := FALSE;
          search_complete := FALSE;
          module_directory^ [i].module_name := old_module_dictionary^ [i].name;
          module_directory^ [i].new_module_number := 0;
          module_directory^ [i].last_section_ordinal := occ$invalid_section_ordinal;
          module_directory^ [i].section_number_change_list := NIL;
          module_directory^ [i].number_of_components := 0;
          module_directory^ [i].number_of_rel_items := 0;
          j := start;
          WHILE NOT match_found AND NOT search_complete DO
            match_found := (old_module_dictionary^ [i].name = new_module_dictionary^ [j].name) AND
                  (old_module_dictionary^ [i].kind = new_module_dictionary^ [j].kind);
            IF match_found THEN
              module_directory^ [i].new_module_number := j;
              start := j + 1;
              IF start > UPPERBOUND (new_module_dictionary^) THEN
                start := 1;
              IFEND;
            ELSE
              j := j + 1;
              IF j > UPPERBOUND (new_module_dictionary^) THEN
                j := 1;
              IFEND;
              search_complete := (j = start);
            IFEND;
          WHILEND;
        FOREND;

        build_module_predictors (new_file_name, old_file_name, old_ol, new_ol, old_module_dictionary,
              new_module_dictionary, module_directory, predictor, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        build_mod_dictionary_ocv (module_directory, old_module_dictionary, new_module_dictionary, old_ol,
              new_ol, predictor, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
      IFEND;
    IFEND;
    build_ol_dictionary_ocv (old_ol, new_ol, predictor, status);
  PROCEND ocp$generate_ol_predictor;
MODEND ocm$generate_predictor;
