?? RIGHT := 110 ??
?? NEWTITLE := 'CREATE_SUBPRODUCT_CORRECTION Utility: GENERATE_CORRECTION Subcommand.' ??
MODULE ram$generate_correction_pacs;

{ PURPOSE:
{   This module contains the interface and procedures to generate
{   a subproduct correction.
{
{ DESIGN:
{   The compiled module resides in RAF$LIBRARY.
{
{   There are two kinds of correction installation schemes currently
{   supported, cycle based and version based.  The following describes how
{   the element list is generated to support these schemes.  The difference
{   between ACTIVE and INACTIVE elements, and the differences between FULL
{   and COMPRESSED element lists is also described.
{
{   The element list provides information about the files and subcatalogs
{   that make up a subproduct.  Usually there is a one to one correlation
{   between the elements in the element list and the files and catalogs in
{   its PACS catalog.  The exception is a version based subproduct
{   correction.  In a version based subproduct correction, element
{   information for the full subproduct, not just those files being
{   corrected, must be kept in the element list.  That is because with
{   version based, the whole subproduct must be must be recreated under the
{   new version catalog.  With cycle based, the files that are not corrected
{   will still be accessable and do not require any recreation.
{
{   To create an element list that can contain element information for the
{   full subproduct and still have an exact understanding of what is in the
{   PACS catalog, elements within the element list are set as active or
{   inactive.  An active element has a corresponding file or catalog in the
{   PACS catalog for that element.  An inactive element is not a member of
{   the PACS catalog.
{
{   Any procedure can determine if a file or catalog should be in the PACS
{   catalog by checking the ACTIVE/INACTIVE attribute.
{
{   The element list for both the version based and cycle based corrections
{   are prepared the same way.  First the element list from the current
{   level is copied into memory (this represents the full element list for
{   the subproduct).  As changes are isolated and corrections generated,
{   element information is updated.  Those elements not required to support
{   a correction are set to inactive.
{
{   When all file corrections have been generated into the PACS catalog, the
{   element list is either kept as full (when version based) or compressed
{   (for cycle based).  Compressing the element list removes all the
{   elements that are inactive.  This is allowed because the information for
{   the rest of the subproduct's files/catalogs is not required to install
{   the correction.
{
{ NOTES:
{

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc pft$path
*copyc rac$sif_file_name
*copyc rae$install_software_cc
*copyc rae$package_software_cc
*copyc rat$path
*copyc rat$validation_selections
?? POP ??
*copyc amp$return
*copyc clp$change_variable
*copyc clp$create_procedure_variable
*copyc clp$delete_variable
*copyc clp$evaluate_parameters
*copyc clp$get_variable
*copyc clp$include_command
*copyc clp$include_line
*copyc clp$trimmed_string_size
*copyc fsp$copy_file
*copyc i#current_sequence_position
*copyc mmp$create_scratch_segment
*copyc mmp$delete_scratch_segment
*copyc osp$append_status_parameter
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc osp$generate_error_message
*copyc osp$set_status_abnormal
*copyc pfp$convert_fs_path_to_pf_path
*copyc pfp$convert_string_to_fs_path
*copyc pfp$define_catalog
*copyc pmp$get_unique_name
*copyc rap$convert_path_to_str
*copyc rap$create_element_list
*copyc rap$generate_object_correction
*copyc rap$locate_element
*copyc rap$reset_correction_environ
*copyc rap$sort_psrs
*copyc rap$validate_installation_paths
*copyc rap$verify_subproduct
*copyc rap$write_file_from_memory
*copyc rap$write_subproduct_info_file
*copyc rav$correction_process_record

?? TITLE := 'Global Declarations Declared by This Module', EJECT ??

{ NOTES:
{   The following constant and type declarations are used by the compare
{   object libraries procedure.  The variable type_specification is
{   suppressed from a compiled listing and is the result of GENPDT on the
{   scl_compare_var_type declaration.
{

  CONST
    scl_compare_variable = 'RAV$COMPARE_OUTPUT_LINE';

{ TYPE
{   scl_compare_var_type: string
{ TYPEND

?? PUSH (LISTEXT := ON) ??
?? FMT (FORMAT := OFF) ??

  VAR
    type_specification : [STATIC, READ, cls$declaration_section] record
      header: clt$type_specification_header,
      name: string (20),
      qualifier: clt$string_type_qualifier,
    recend := [
      [1, 20, clc$string_type], 'SCL_COMPARE_VAR_TYPE', [0, clc$max_string_size, FALSE]];

?? FMT (FORMAT := ON) ??
?? POP ??

?? OLDTITLE ??
?? NEWTITLE := '[XDCL] rap$generate_correction_pacs', EJECT ??

{ PURPOSE:
{   This interface is used to generate a correction to the base level PACS
{   catalog specified on the DEFINE_CORRECTION subcommand.  The correction
{   will make the files the same as those in the current level PACS catalog
{   also specified on the DEFINE_CORRECTION command.
{
{ DESIGN:
{   A DEFINE_CORRECTION command must have preceded this subcommand.
{   DEFINE_CORRECTION sets up the correction process record used here to
{   control processing.  It also initializes the subproduct info sequence
{   for the new PACS catalog (the correction) with a copy of the subproduct
{   info sequence from the current level catalog.
{
{   The steps involved in generating the correction for a subproduct
{   are as follows:
{
{   1.  Create the catalog that will contain the PACS catalog for the
{       correction.  The catalog path was specified by the PACS_CATALOG
{       parameter.  If not validated to create the catalog return with
{       error, but leave the environment intact.  (The root PACS catalog
{       must not exist prior to calling this interface.)
{
{   2.  Isolate all subproduct changes.  Corrections are generated for all
{       files which have changed and for which no previous correction is
{       available.  Corrections are carried forward from the previous correction
{       catalog if a file changes and the previous correction will correct the
{       file.  Generated corrections and those brought forward are placed in the
{       new PACS catalog.  The element list from the new subproduct info
{       sequence is used to drive the correction generation.
{
{       The element information for the corrected files will be taken from
{       the current level SIF when the correction was generated from the
{       current level and from the previous correction SIF when the
{       correction was carried forward.
{
{       If no changes are found the processing will continue with step 5,
{       and a warning message will be returned.
{
{   3.  Add the PSRs answered to the new subproduct info sequence found
{       in memory.  This means merging the PSRs answered from a previous
{       correction (when present) with the current PSRs answered already
{       on the new subproduct info sequence (when present).
{
{   4.  Write the new subproduct info sequence from memory to the permanent
{       file SIF in the new PACS catalog.  This is to include compressing
{       the element list when the correction installation scheme is cycle
{       based (see discussion on the element list in the module design
{       section).
{
{   5.  Close all the SIFs used in creating the new PACS catalog.
{       Set a flag to indicate that the correction has been generated and that no
{       correction is currently being processed.  When an error or abort
{       situation is encountered, delete the new PACS catalog and contents.
{
{ NOTES:
{   An element path is that portion of a file or catalog path that can be
{   constructed using the element list.  To create a complete file or catalog
{   path, the PACS catalog path must be added to the front of the
{   element path for that file or catalog.  The element path is processed
{   using PF path format, because it is the most efficient when it comes to
{   locating the same element in multiple element lists.  The procedure
{   isolate_subproduct_changes requires the PF path container for the
{   element path to be initialized to an array of one.
{

  PROCEDURE [XDCL] rap$generate_correction_pacs
    (    parameter_list: clt$parameter_list;
     VAR status: ost$status);



{ PROCEDURE genc_pdt (
{ pacs_catalog, pc : file = $required
{ status)

?? PUSH (LISTEXT := ON) ??

    VAR
      pdt: [STATIC, READ, cls$declaration_section] record
        header: clt$pdt_header,
        names: array [1 .. 3] of clt$pdt_parameter_name,
        parameters: array [1 .. 2] of clt$pdt_parameter,
        type1: record
          header: clt$type_specification_header,
        recend,
        type2: record
          header: clt$type_specification_header,
        recend,
      recend := [[1, [88, 8, 18, 8, 56, 21, 467], clc$command, 3, 2, 1, 0, 0, 0, 2, 'GENC_PDT'],
            [['PACS_CATALOG                   ', clc$nominal_entry, 1],
            ['PC                             ', clc$abbreviation_entry, 1],
            ['STATUS                         ', clc$nominal_entry, 2]], [
{ PARAMETER 1
      [1, clc$normal_usage_entry, clc$non_secure_parameter, $clt$parameter_spec_methods
            [clc$specify_by_name, clc$specify_positionally], clc$pass_by_value, clc$immediate_evaluation,
            clc$standard_parameter_checking, 3, clc$required_parameter, 0, 0],
{ PARAMETER 2
      [3, clc$normal_usage_entry, clc$non_secure_parameter, $clt$parameter_spec_methods [clc$specify_by_name],
            clc$pass_by_reference, clc$immediate_evaluation, clc$standard_parameter_checking, 3,
            clc$optional_parameter, 0, 0]],
{ PARAMETER 1
      [[1, 0, clc$file_type]],
{ PARAMETER 2
      [[1, 0, clc$status_type]]];

?? POP ??

    CONST
      p$pacs_catalog = 1,
      p$status = 2;

    VAR
      pvt: array [1 .. 2] of clt$parameter_value;


    VAR
      corrections_generated: boolean,
      element_path_p: ^pft$path,
      fs_path: fst$path,
      ignore_corr_carried_forward: boolean,
      ignore_cycle_reference: fst$cycle_reference,
      ignore_cycle_selector: clt$cycle_selector,
      ignore_open_position: fst$open_position,
      ignore_status: ost$status,
      local_status: ost$status,
      new_pacs_catalog_path_p: ^pft$path,
      new_sif: rat$path,
      new_subproduct_info_ptrs: rat$subproduct_info_pointers,
      active_element_count: rat$element_count,
      number_of_path_elements: fst$number_of_path_elements,
      pacs_length: integer,
      sif_length: integer,
      validation_selections: rat$validation_selections,
      verify_errors: rat$subproduct_verify_errors,
      verify_options: rat$subproduct_verify_options;

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

{ PURPOSE:
{   This procedure cleans up when an abort situation occurs within the
{   block structure.
{
{ DESIGN:
{   The function of this condition handler is to delete the new PACS catalog
{   when an abort condition arises.
{
{ 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;

      delete_new_pacs_catalog (pvt [p$pacs_catalog].value^.file_value^, ignore_status);

    PROCEND abort_handler;

?? OLDTITLE, EJECT ??

    status.normal := TRUE;

    clp$evaluate_parameters (parameter_list, #SEQ (pdt), NIL, ^pvt, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF NOT rav$correction_process_record.correction_in_progress THEN
      osp$set_status_abnormal ('RA', rae$defc_command_not_called, 'GENERATE_CORRECTION', status);
      RETURN;
    IFEND;

    new_subproduct_info_ptrs := rav$correction_process_record.new_subproduct_info_pointers;

    rap$validate_installation_paths (rav$correction_process_record.base_level_sif.
          subproduct_info_pointers.attributes_p^, rav$correction_process_record.base_level_sif.
          subproduct_info_pointers.path_container_p^, rav$correction_process_record.current_level_sif.
          subproduct_info_pointers.attributes_p^, rav$correction_process_record.current_level_sif.
          subproduct_info_pointers.path_container_p^, new_subproduct_info_ptrs.attributes_p^.
          installation_scheme, TRUE {set_status_to_error}, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    {Convert the PACS_CATALOG parameter value into rat$path format and store it in the new
    {subproduct info sequence attributes record.

    pacs_length := clp$trimmed_string_size (pvt [p$pacs_catalog].value^.file_value^);
    new_subproduct_info_ptrs.attributes_p^.pacs_catalog_path.path := '';
    new_subproduct_info_ptrs.attributes_p^.pacs_catalog_path.path (1,
          pacs_length) := pvt [p$pacs_catalog].value^.file_value^;
    new_subproduct_info_ptrs.attributes_p^.pacs_catalog_path.size := pacs_length;

    pfp$convert_string_to_fs_path (pvt [p$pacs_catalog].value^.file_value^, fs_path, number_of_path_elements,
          ignore_cycle_reference, ignore_open_position, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    PUSH new_pacs_catalog_path_p: [1 .. number_of_path_elements];
    pfp$convert_fs_path_to_pf_path (fs_path, new_pacs_catalog_path_p, ignore_cycle_reference,
          ignore_cycle_selector, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pfp$define_catalog (new_pacs_catalog_path_p^, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    osp$establish_block_exit_hndlr (^abort_handler);

  /main/
    BEGIN

      { Create an SCL boolean variable to be used when comparing object libraries.
      { The variable type_specification is defined in the global declarations section.

      clp$create_procedure_variable (scl_compare_variable, clc$local_scope, clc$read_write,
            clc$immediate_evaluation, #SEQ (type_specification), NIL, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      { Initialize element path container to one element.

      PUSH element_path_p: [1 .. 1];

      isolate_subproduct_changes (element_path_p, new_pacs_catalog_path_p,
            new_subproduct_info_ptrs.element_list_p, rav$correction_process_record, active_element_count,
            corrections_generated, ignore_corr_carried_forward, status);
      clp$delete_variable (scl_compare_variable, ignore_status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;
      new_subproduct_info_ptrs.attributes_p^.first_level_element_count := active_element_count;

      IF NOT corrections_generated THEN
        osp$set_status_abnormal ('RA', rae$no_corrections_generated,
              rav$correction_process_record.current_level_sif.subproduct_info_pointers.attributes_p^.name,
              status);
        EXIT /main/;
      IFEND;

      { After the new PACS catalog (containing the corrections) has been generated,
      { the subproduct information sequence is completed and the subproduct information file
      { is written from the memory sequence.

      {If a previous correction was specified and it contains a PSRs answered list.
      IF rav$correction_process_record.previous_correction_sif.file_opened AND
            (rav$correction_process_record.previous_correction_sif.subproduct_info_pointers.
            psrs_answered_p <> NIL) THEN

        add_psrs_answered_to_seq (rav$correction_process_record.previous_correction_sif.
              subproduct_info_pointers.psrs_answered_p, new_subproduct_info_ptrs.info_header_p,
              new_subproduct_info_ptrs.psrs_answered_p, new_subproduct_info_ptrs.subproduct_info_seq_p,
              status);
        IF NOT status.normal THEN
          EXIT /main/;
        IFEND;
      IFEND;

      IF new_subproduct_info_ptrs.attributes_p^.installation_scheme = rac$cycle_based THEN

        write_compressed_sif (element_path_p, new_subproduct_info_ptrs, status);

      ELSE {installation scheme is version based}

        { Call verify_subproduct to set the attributes_checksum, modification_date_time, product_size,
        { and subproduct_size fields.

        verify_errors := $rat$subproduct_verify_errors [];
        validation_selections := $rat$validation_selections [];
        verify_options := $rat$subproduct_verify_options [rac$reconcile_mod_date_time, rac$calculate_size,
              rac$get_attributes_checksum];

        rap$verify_subproduct (pvt [p$pacs_catalog].value^.file_value, validation_selections, FALSE
              {sif_present} , verify_options, verify_errors, new_subproduct_info_ptrs, status);
        IF NOT status.normal THEN
          EXIT /main/;
        IFEND;

        STRINGREP (new_sif.path, new_sif.size, pvt [p$pacs_catalog].value^.file_value^, '.',
              rac$sif_file_name);

        rap$write_file_from_memory (new_sif.path (1, new_sif.size),
              i#current_sequence_position (new_subproduct_info_ptrs.subproduct_info_seq_p),
              new_subproduct_info_ptrs.subproduct_info_seq_p, status);


      IFEND;

    END /main/;

    IF NOT status.normal THEN
      delete_new_pacs_catalog (pvt [p$pacs_catalog].value^.file_value^, ignore_status);
    IFEND;

    {Close all the SIFs used in creating the new PACS catalog
    {and reset all booleans in the correction process record to FALSE.

    rap$reset_correction_environ (rav$correction_process_record, local_status);

    osp$disestablish_cond_handler;

    IF status.normal AND (NOT local_status.normal) THEN
      status := local_status;
    IFEND;

  PROCEND rap$generate_correction_pacs;

?? OLDTITLE ??
?? NEWTITLE := 'construct_full_path', EJECT ??

{ PURPOSE:
{   This procedure constructs a files full path by putting the PACS catalog
{   together with the rest of the file path.
{
{ DESIGN:
{   This procedure combines the PACS catalog path in rat$path format with
{   the rest of the element path which is in pft$path format.  The returned
{   full path is in rat$path format.
{
{ NOTES:
{

  PROCEDURE construct_full_path
    (    pacs_catalog: rat$path;
         element_path_p: ^pft$path;
     VAR full_path: rat$path);


    VAR
      file_path: rat$path;

    rap$convert_path_to_str (element_path_p^, file_path);

    { rap$convert_path_to_str returns with the first character as a ':' .
    { Therefore the STRINGREP only uses from character 2 to the end of the file path.

    STRINGREP (full_path.path, full_path.size, pacs_catalog.path (1, pacs_catalog.size),
          '.', file_path.path (2, file_path.size - 1));

  PROCEND construct_full_path;

?? OLDTITLE ??
?? NEWTITLE := 'delete_new_pacs_catalog', EJECT ??

{ PURPOSE:
{   This procedure deletes the new PACS catalog and all of its contents.
{
{ DESIGN:
{   This procedure uses the SCL delete_catalog command to delete the
{   new PACS catalog and its contents.
{
{ NOTES:
{

  PROCEDURE delete_new_pacs_catalog
    (    pacs_catalog_ref: fst$file_reference;
     VAR status: ost$status);


    VAR
      command_line: string (osc$max_string_size),
      command_line_length: integer,
      enable_echoing: boolean;

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

    STRINGREP (command_line, command_line_length, 'DELETE_CATALOG CATALOG = ', pacs_catalog_ref,
          ' DELETE_OPTION = CATALOG_AND_CONTENTS');

    clp$include_command (command_line (1, command_line_length), enable_echoing, status);

  PROCEND delete_new_pacs_catalog;

?? OLDTITLE ??
?? NEWTITLE := 'add_psrs_answered_to_seq', EJECT ??

{ PURPOSE:
{   This procedure merges the PSRs answered by this correction with the
{   psrs answered during a previous correction.
{
{ DESIGN:
{   This procedure is called only if a previous correction exists.
{
{   The PSRs answered by this correction are merged with the PSRs
{   answered by the previous correction, sorted, and written to the
{   new subproduct info sequence.
{
{   The relative pointer to the PSRs answered section and the PSRs answered
{   count must be set in the subproduct info header.
{
{ NOTES:
{

  PROCEDURE add_psrs_answered_to_seq
    (    previous_psrs_answered_p: ^rat$psrs_answered;
         new_info_header_p: ^rat$subproduct_info_header;
     VAR new_psrs_answered_p: ^rat$psrs_answered;
     VAR new_subproduct_info_seq_p: ^rat$subproduct_info_sequence;
     VAR status: ost$status);

    VAR
      previous_psrs_p: ^rat$psrs_answered;

    status.normal := TRUE;

    NEXT previous_psrs_p: [1 .. UPPERBOUND (previous_psrs_answered_p^)] IN new_subproduct_info_seq_p;
    IF previous_psrs_p = NIL THEN
      osp$set_status_abnormal ('RA', rae$accessed_beyond_segment_eoi, 'NEW SUBPRODUCT_INFO_SEQUENCE', status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'initial creation', status);
      RETURN;
    IFEND;
    previous_psrs_p^ := previous_psrs_answered_p^;

    IF new_psrs_answered_p <> NIL THEN
      RESET new_subproduct_info_seq_p TO new_psrs_answered_p;
      NEXT new_psrs_answered_p: [1 .. UPPERBOUND (new_psrs_answered_p^) +
            UPPERBOUND (previous_psrs_answered_p^)] IN new_subproduct_info_seq_p;
    ELSE
      RESET new_subproduct_info_seq_p TO previous_psrs_p;
      NEXT new_psrs_answered_p: [1 .. UPPERBOUND (previous_psrs_answered_p^)] IN new_subproduct_info_seq_p;
    IFEND;

    rap$sort_psrs (new_psrs_answered_p^);
    new_info_header_p^.psrs_answered_p := #REL (new_psrs_answered_p, new_subproduct_info_seq_p^);

  PROCEND add_psrs_answered_to_seq;

?? TITLE := 'compare_object_libraries', EJECT ??

{ PURPOSE:
{   This procedure compares two object libraries and returns the result in a
{   boolean.  The comparison is done so that the time/date stamps within the
{   libraries are ignored.  This prevents a correction from being generated
{   for a library that has been recompiled without any actual modifications.
{
{ DESIGN:
{   The compare is performed using COMPARE_OBJECT_LIBRARY (COMOL) which is only
{   callable through command language.  To accomplish this, the SCL commands
{   must be collected and executed by including the lines.
{
{   COMOL places the results of the compare into an output file.  The file
{   contents must then be interpreted.  When two libraries compare, the
{   compare output file will contain only 1 line and the line will have the
{   same string value as that assigned to the compare_line constant below.
{
{   The 1st line of the compare output file is retrieved to the CYBIL side.
{   The value of the line is compared with the value of a line from a
{   successful compare.
{
{ NOTES:
{   The SCL_COMPARE_VARIABLE is a global string constant that is used
{   as the name of the scl compare variable.
{
{   The SCL commands that are assembled by STRINGREP into the command
{   line have been arranged for readability.  Formating has been turned
{   off to protect these lines from the formater.
{

  PROCEDURE compare_object_libraries
    (    library: rat$path;
         with_library: rat$path;
     VAR libraries_compare: boolean;
     VAR status: ost$status);


    CONST
      compare_line = '-Number of compare errors: 0';

    VAR
      access_mode: clt$data_access_mode,
      class: clt$variable_class,
      command_line: string (1000),
      command_line_length: integer,
      compare_output: rat$path,
      evaluation_method: clt$expression_eval_method,
      ignore_status: ost$status,
      scl_compare_value_p: ^clt$data_value,
      scratch_seq_p: ^SEQ ( * ),
      type_specification_p: ^clt$type_specification,
      unique_file_name: ost$name;


    status.normal := TRUE;

    { Establish the size of the scratch sequence used to store the SCL compare variable value.
    { The variable type_specification is defined in the global declaration section.

    PUSH scratch_seq_p: [[REP #SIZE (clt$data_value) + #SIZE (type_specification) of cell]];

    { Build a unique file path to be used by the SCL compare command to put the compare results.

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

    STRINGREP (compare_output.path, compare_output.size, ':$LOCAL.',
          unique_file_name (1, clp$trimmed_string_size (unique_file_name)));

    { Collect the SCL commands required to compare the libraries.

?? FMT (FORMAT := OFF) ??
    STRINGREP (command_line, command_line_length,
          ' $system.set_file_attributes f=', compare_output.path (1, compare_output.size),
          '       page_format=continuous;',
          ' $system.compare_object_library f=', library.path (1, library.size),
          '       w=', with_library.path (1, with_library.size),
          '       o=', compare_output.path (1, compare_output.size), ';',
          ' $system.get_line v=', scl_compare_variable,
          '       i=', compare_output.path (1, compare_output.size));
?? FMT (FORMAT := ON) ??

    { Execute the SCL commands and retrieve the first compare output line.

    clp$include_line (command_line (1, command_line_length), TRUE, osc$null_name, status);
    amp$return (compare_output.path (1, compare_output.size), ignore_status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clp$get_variable (scl_compare_variable, scratch_seq_p, class, access_mode, evaluation_method,
          type_specification_p, scl_compare_value_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    { The value of the first compare output line is compared with the value of a line from a
    { successful compare.  If they are equal the libraries compare.

    libraries_compare := (scl_compare_value_p^.string_value^ = compare_line);

  PROCEND compare_object_libraries;

?? OLDTITLE ??
?? NEWTITLE := 'copy_element_info', EJECT ??

{ PURPOSE:
{   This procedure copies certain element information from one element
{   record to another element record.
{
{ DESIGN:
{   The following element information is copied from the first variable to
{   the second variable when the element is a file.
{
{          base_contents_checksum          pre_genc_contents_checksum
{          correction_format                     ring_attributes
{          library_merge                         storage_class
{          permit
{
{   When the element is a catalog, only the permit information is copied.
{
{   The fields that are element list dependent (ie.  the relative pointers
{   between element records) are already correct.  The processing attributes
{   are set to active in isolate subproduct changes.
{
{ NOTES:
{

  PROCEDURE copy_element_info
    (    from_element_p: ^rat$element;
         to_element_p {output} : ^rat$element);


    IF from_element_p^.element_type = rac$file THEN

      to_element_p^.correction_base_contents_cksum := from_element_p^.correction_base_contents_cksum;
      to_element_p^.correction_format := from_element_p^.correction_format;
      to_element_p^.library_merge := from_element_p^.library_merge;
      to_element_p^.permit := from_element_p^.permit;
      to_element_p^.pre_genc_contents_checksum := from_element_p^.pre_genc_contents_checksum;
      to_element_p^.ring_attributes := from_element_p^.ring_attributes;
      to_element_p^.storage_class := from_element_p^.storage_class;

    ELSE {rac$catalog}

      to_element_p^.permit := from_element_p^.permit;

    IFEND;

  PROCEND copy_element_info;

?? OLDTITLE ??
?? NEWTITLE := 'create_pacs_subcatalogs', EJECT ??

{ PURPOSE:
{   This procedure creates the necessary subcatalogs within the PACS
{   catalog so that correction files may be created in the subcatalog.
{
{ DESIGN:
{   This procedure attempts to create all subcatalogs below the PACS catalog
{   leading to the file.
{
{ NOTES:
{

  PROCEDURE create_pacs_subcatalogs
    (    new_pacs_catalog_path_p: ^pft$path;
         element_path_p: ^pft$path);

    VAR
      full_catalog_path_p: ^pft$path,
      i: fst$number_of_path_elements,
      ignore_status: ost$status,
      j: fst$number_of_path_elements,
      new_subcatalog_p: ^pft$path,
      number_of_subcatalogs: fst$number_of_path_elements,
      path_sequence_p: ^SEQ ( * ),
      subcatalogs: integer;


    j := 1;
    PUSH full_catalog_path_p: [1 .. UPPERBOUND (new_pacs_catalog_path_p^) + UPPERBOUND (element_path_p^)];

    FOR i := 1 TO UPPERBOUND (new_pacs_catalog_path_p^) DO
      full_catalog_path_p^ [j] := new_pacs_catalog_path_p^ [i];
      j := j + 1;
    FOREND;

    FOR i := 1 TO UPPERBOUND (element_path_p^) DO
      full_catalog_path_p^ [j] := element_path_p^ [i];
      j := j + 1;
    FOREND;

    PUSH path_sequence_p: [[REP #SIZE (full_catalog_path_p^) OF cell]];
    RESET path_sequence_p;
    NEXT new_subcatalog_p: [1 .. UPPERBOUND (full_catalog_path_p^)] IN path_sequence_p;
    new_subcatalog_p^ := full_catalog_path_p^;

    number_of_subcatalogs := UPPERBOUND (full_catalog_path_p^) - UPPERBOUND (new_pacs_catalog_path_p^) - 1;
    {Subtract 1 for the file name} ;

    FOR subcatalogs := 1 TO number_of_subcatalogs DO

      RESET path_sequence_p;
      NEXT new_subcatalog_p: [1 .. UPPERBOUND (new_pacs_catalog_path_p^) + subcatalogs] IN path_sequence_p;

      pfp$define_catalog (new_subcatalog_p^, ignore_status);

    FOREND;

  PROCEND create_pacs_subcatalogs;

?? OLDTITLE ??
?? NEWTITLE := 'generate_file_correction', EJECT ??

{ PURPOSE:
{   This procedure generates a correction for the file.
{
{ DESIGN:
{   The correction formats currently being supported are REPLACEMENT,
{   SOURCE LIBRARY and OBJECT LIBRARY.  Files that are neither source
{   library nor object library must use the replacement format.
{
{   When the correction format is REPLACEMENT the current level file is
{   taken as the correction.  The current level file is copied directly
{   into the new PACS catalog for the correction.  No correction is
{   actually generated.
{
{   When the format is OBJECT LIBRARY or SOURCE LIBRARY the correction is
{   generated by comparing the current level file to the base level file.
{   The resulting correction is written to a file under the new PACS catalog.
{
{   When an error is returned while attempting to generate a correction of
{   format object library or source library, the correction format is
{   automatically changed to replacement and the current level file is
{   copied directly into the new PACS catalog.  A warning message is
{   displayed along with the error that occured.
{
{   The destination location in the new PACS catalog for the
{   file is identical to its location in the current level PACS catalog.
{
{ NOTES:
{   An element path is that portion of a file or catalog path that is
{   represented by the element list.  To create a complete file or catalog
{   path, the PACS catalog path must be appended to the front of the
{   element path for that file or catalog.  The paths are converted to FST$PATH
{   format.
{

  PROCEDURE generate_file_correction
    (    element_path_p: ^pft$path;
         new_pacs_catalog_path_p: ^pft$path;
         base_pacs_catalog: rat$path;
         current_pacs_catalog: rat$path;
         new_pacs_catalog: rat$path;
         base_checksum: rat$checksum;
         current_checksum: rat$checksum;
         element_p {input/output} : ^rat$element;
     VAR status: ost$status);


    VAR
      base_file: rat$path,
      current_file: rat$path,
      ignore_status: ost$status,
      local_status: ost$status,
      new_file: rat$path;


*copy rav$correction_format

    status.normal := TRUE;
    local_status.normal := TRUE;
    base_file.path := '';
    current_file.path := '';
    new_file.path := '';

    { Assemble the base file, current file and new file paths.

    construct_full_path (base_pacs_catalog, element_path_p, base_file);
    construct_full_path (current_pacs_catalog, element_path_p, current_file);
    construct_full_path (new_pacs_catalog, element_path_p, new_file);

    { Create any non-existing subcatalogs along new file path.
    create_pacs_subcatalogs (new_pacs_catalog_path_p, element_path_p);


    IF element_p^.correction_format = rac$object_library THEN

      rap$generate_object_correction (base_file.path (1, base_file.size),
            current_file.path (1, current_file.size), new_file.path (1, new_file.size),
            FALSE {calculate_checksums}, base_checksum, current_checksum, element_p, local_status);

    ELSE {rac$replacement or rac$source_library}

      { Copy the file from current level PACS catalog to the new PACS catalog.

      fsp$copy_file (current_file.path (1, current_file.size), new_file.path (1, new_file.size),
            NIL, NIL, NIL, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

    IFEND;

    IF NOT local_status.normal THEN

      { Handle correction as file replacement.
      { Display a warning message.  Then change the correction format in element to replacement.

      osp$set_status_abnormal ('RA', rae$correction_format_changed, new_file.path (1, new_file.size),
            local_status);
      osp$append_status_parameter (osc$status_parameter_delimiter,
            rav$correction_format [element_p^.correction_format], local_status);
      osp$generate_error_message (local_status, ignore_status);

      element_p^.correction_format := rac$replacement;

      { Copy the file from current level PACS catalog to the new PACS catalog.

      fsp$copy_file (current_file.path (1, current_file.size), new_file.path (1, new_file.size),
            NIL, NIL, NIL, status);

    IFEND;

  PROCEND generate_file_correction;

?? OLDTITLE ??
?? NEWTITLE := 'isolate_file_changes', EJECT ??

{ PURPOSE:
{   This procedure determines if a file has changed and causes a correction
{   to be generated or copied forward as appropriate.
{
{ DESIGN:
{   When a previous correction exists for the file, changes are discovered
{   by comparing the file's current level contents_checksum against the
{   previous correction's pre_genc_contents_checksum.  Pre_genc refers to
{   the file used against the base in generating the correction.
{
{   When the file is an object library and the previous correction is of type
{   replacement (ie.  it is a complete object library, not a patch), the
{   file undergoes an additional byte comparison that ignores the date/time
{   stamps.  This prevents a correction from being generated for a file that
{   has been recompiled without any actual modifications.
{
{   When a previous correction does not exist for the file, changes are
{   discovered by comparing the file's current level contents checksum
{   against the file's base level contents checksum.
{
{   The checksums were generated during subproduct definition and are
{   stored in the respective SIFs.
{
{   When differences are found a correction will be generated based on the
{   correction format.
{
{   When a previous correction exists for a file and the file has not
{   changed since that level, the correction is carried forward into the
{   new PACS catalog.
{
{ NOTES:
{   It is assumed that the element lists were originally generated with
{   checksums and that the element lists of the base level and current level
{   contain the same elements.  Also assumed is that the element list of the
{   previous correction is a subset of the current level element list.
{   This was checked by RAP$DEFINE_CORRECTION.
{

  PROCEDURE isolate_file_changes
    (    element_path_p: ^pft$path;
         new_pacs_catalog_path_p: ^pft$path;
         correction_process_record {input/output} : rat$correction_process_record;
         element_p {input/output} : ^rat$element;
     VAR new_correction_generated: boolean;
     VAR previous_correction_used: boolean;
     VAR status: ost$status);


    VAR
      base_subproduct_info_ptrs: rat$subproduct_info_pointers,
      current_file_path: rat$path,
      current_subproduct_info_ptrs: rat$subproduct_info_pointers,
      libraries_compare: boolean,
      new_file_path: rat$path,
      new_subproduct_info_ptrs: rat$subproduct_info_pointers,
      prev_correction_element_p: ^rat$element,
      previous_correction_file: rat$path,
      previous_element_p: ^rat$element,
      previous_element_found: boolean,
      previous_file_path: rat$path,
      previous_subproduct_info_ptrs: rat$subproduct_info_pointers;


    status.normal := TRUE;
    new_correction_generated := FALSE;
    previous_correction_used := FALSE;
    base_subproduct_info_ptrs := correction_process_record.base_level_sif.subproduct_info_pointers;
    current_subproduct_info_ptrs := correction_process_record.current_level_sif.subproduct_info_pointers;
    new_subproduct_info_ptrs := correction_process_record.new_subproduct_info_pointers;

    IF correction_process_record.previous_correction_sif.file_opened THEN
      previous_subproduct_info_ptrs := correction_process_record.previous_correction_sif.
            subproduct_info_pointers;

      previous_element_p := previous_subproduct_info_ptrs.element_list_p;
      rap$locate_element (element_path_p, 1 {path_index} , previous_subproduct_info_ptrs.
            subproduct_info_seq_p, previous_element_p, previous_element_found);

      IF previous_element_found AND previous_element_p^.active_element THEN

        construct_full_path (previous_subproduct_info_ptrs.attributes_p^.pacs_catalog_path, element_path_p,
              previous_file_path);
        construct_full_path (new_subproduct_info_ptrs.attributes_p^.pacs_catalog_path, element_path_p,
              new_file_path);

        { Compare the contents checksums from the current level file against the
        {  previous correction's pre-GENC contents checksum.

        IF element_p^.contents_checksum = previous_element_p^.pre_genc_contents_checksum THEN

          { File has not changed since the previous correction.
          { Move the file from the previous correction to the new PACS catalog.

          use_previous_correction (element_path_p, new_pacs_catalog_path_p, new_file_path,
                previous_file_path, previous_element_p, element_p, previous_correction_used, status);

        ELSE  { Contents checksums do not match }

          IF (element_p^.file_contents_and_structure = rac$object_library) AND
                (previous_element_p^.correction_format = rac$replacement) THEN

            { The previous correction is a complete object library.
            { Compare files ignoring time/date stamps.

            construct_full_path (current_subproduct_info_ptrs.attributes_p^.pacs_catalog_path,
                  element_path_p, current_file_path);

            compare_object_libraries (current_file_path, previous_file_path, libraries_compare, status);
            IF NOT status.normal THEN
              RETURN;
            IFEND;

            IF libraries_compare THEN

              { File has not changed since the previous correction.
              { Move the file from the previous correction to the new PACS catalog.

              use_previous_correction (element_path_p, new_pacs_catalog_path_p, new_file_path,
                    previous_file_path, previous_element_p, element_p, previous_correction_used, status);

            ELSE { libraries do not compare }

              isolate_file_changes_using_base (element_path_p, new_pacs_catalog_path_p,
                    current_subproduct_info_ptrs, new_subproduct_info_ptrs, element_p,
                    new_correction_generated, base_subproduct_info_ptrs, status);

            IFEND;
          ELSE { not an object library or previous correction is a patch and cannot be compared }

            isolate_file_changes_using_base (element_path_p, new_pacs_catalog_path_p,
                  current_subproduct_info_ptrs, new_subproduct_info_ptrs, element_p, new_correction_generated,
                  base_subproduct_info_ptrs, status);

          IFEND;
        IFEND;

      ELSE {previous correction does not exist}

        isolate_file_changes_using_base (element_path_p, new_pacs_catalog_path_p,
              current_subproduct_info_ptrs, new_subproduct_info_ptrs, element_p, new_correction_generated,
              base_subproduct_info_ptrs, status);

      IFEND;

    ELSE {previous correction not used}

      isolate_file_changes_using_base (element_path_p, new_pacs_catalog_path_p, current_subproduct_info_ptrs,
            new_subproduct_info_ptrs, element_p, new_correction_generated, base_subproduct_info_ptrs, status);

    IFEND;

  PROCEND isolate_file_changes;

?? OLDTITLE ??
?? NEWTITLE := 'isolate_file_changes_using_base', EJECT ??

{ PURPOSE:
{   This procedure isolates any file changes between the current level file
{   and the base level file.  When differences are found a file correction
{   is generated.
{
{ DESIGN:
{   Compare the file's current level contents checksum against the file's
{   base level contents checksum.
{
{   When the format is object library, the file undergoes an additional byte
{   comparison that ignores the date/time stamp.  This prevents a correction
{   from being generated for a file that has been recompiled without any
{   actual modifications.
{
{   If the checksums differ and (as required) the object library compare
{   indicates changes, a correction will be generated.
{
{ NOTES:
{   The element information for the corrected file is taken from the current
{   level SIF.  (Since the current level is already in the new subproduct
{   info sequence only the base and pre-GENC checksum fields must be filled in.)
{
{   It is assumed that the element lists were originally generated with
{   checksums.  This was checked by RAP$DEFINE_CORRECTION.
{

  PROCEDURE isolate_file_changes_using_base
    (    element_path_p: ^pft$path;
         new_pacs_catalog_path_p: ^pft$path;
         current_subproduct_info_ptrs: rat$subproduct_info_pointers;
         new_subproduct_info_ptrs: rat$subproduct_info_pointers;
         element_p {input/output} : ^rat$element;
     VAR new_correction_generated: boolean;
     VAR base_subproduct_info_ptrs: rat$subproduct_info_pointers;
     VAR status: ost$status);


    VAR
      base_element_found: boolean,
      base_element_p: ^rat$element,
      base_file_path: rat$path,
      current_file_path: rat$path,
      libraries_compare: boolean;


    status.normal := TRUE;
    base_element_p := base_subproduct_info_ptrs.element_list_p;

    rap$locate_element (element_path_p, 1 {path_index} , base_subproduct_info_ptrs.subproduct_info_seq_p,
          base_element_p, base_element_found);

    { Compare the contents checksums from the current level file against the base level file.

    IF element_p^.contents_checksum <> base_element_p^.contents_checksum THEN

      IF element_p^.file_contents_and_structure = rac$object_library THEN

        { Compare the object libraries ignoring time/date stamps.

        construct_full_path (base_subproduct_info_ptrs.attributes_p^.pacs_catalog_path, element_path_p,
              base_file_path);
        construct_full_path (current_subproduct_info_ptrs.attributes_p^.pacs_catalog_path,
              element_path_p, current_file_path);

        compare_object_libraries (current_file_path, base_file_path, libraries_compare, status);
        IF (NOT status.normal) OR libraries_compare THEN
          RETURN;
        IFEND;
      IFEND;

      new_correction_generated := TRUE;

      { Set file's base and pre-GENC contents checksums.

      element_p^.correction_base_contents_cksum := base_element_p^.contents_checksum;
      element_p^.pre_genc_contents_checksum := element_p^.contents_checksum;

      { Generate file correction between the base level and the current level.

      generate_file_correction (element_path_p, new_pacs_catalog_path_p,
            base_subproduct_info_ptrs.attributes_p^.pacs_catalog_path,
            current_subproduct_info_ptrs.attributes_p^.pacs_catalog_path,
            new_subproduct_info_ptrs.attributes_p^.pacs_catalog_path, base_element_p^.contents_checksum,
            element_p^.contents_checksum, element_p, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      { Increment the product_file_size or the service_critical_file_size in the attributes record.

      IF element_p^.storage_class = rmc$msc_system_permanent_files THEN
        new_subproduct_info_ptrs.attributes_p^.service_critical_file_size :=
              new_subproduct_info_ptrs.attributes_p^.service_critical_file_size + element_p^.size;
      ELSEIF element_p^.storage_class = rmc$msc_user_permanent_files THEN
        new_subproduct_info_ptrs.attributes_p^.user_permanent_file_size :=
              new_subproduct_info_ptrs.attributes_p^.user_permanent_file_size + element_p^.size;
      ELSE
        new_subproduct_info_ptrs.attributes_p^.product_file_size :=
              new_subproduct_info_ptrs.attributes_p^.product_file_size + element_p^.size;
      IFEND;

    IFEND;

  PROCEND isolate_file_changes_using_base;

?? OLDTITLE ??
?? NEWTITLE := 'isolate_subproduct_changes', EJECT ??

{ PURPOSE:
{   The purpose of this interface is to locate all the changes for the
{   subproduct and produce a new PACS catalog containing newly generated
{   corrections or corrections brought forward from a previous correction.
{   During this process the element list is updated.
{
{ DESIGN:
{   This procedure traverses the element list from the new subproduct info
{   sequence (which is a copy of the the current level subproduct SIF).  For
{   every file belonging to the subproduct, changes are discovered by
{   comparing the checksum of the current level of the file against the previous correction
{   (when found) or the base level of the file (when the previous correction
{   is not found).  Those files with changes will have corrections generated
{   based on the correction format.  A boolean is returned flagging whether
{   or not corrections have been generated or corrections were brought
{   forward.
{
{   Determining what files belong to the subproduct is accomplished by
{   traversing the element list for the subproduct.  The traverse is
{   performed using recursion and each call to ISOLATE_SUBPRODUCT_CHANGES
{   moves processing down to the next catalog level.
{
{   If no new correction was generated or no previous correction was brought
{   forward while processing an element, that element is set as inactive.
{   The elements were originally set to active when the element list was
{   first created.  Once the element list is processed those elements still
{   active will reflect how the new PACS catalog looks.  (See the discussion
{   on element lists in the module design section.)
{
{   The actual isolation of any file changes and generation of the
{   correction if changes found is done by another procedure.
{
{ NOTES:
{   An element path is that portion of a file or catalog path that is
{   represented by the element list.  To create a complete file or catalog
{   path, the PACS catalog path must be appended to the front of the
{   element path for that file or catalog.  The element path is processed
{   using PF path format, because it is the most efficient when it comes to
{   locating the same element in multiple element lists.  The procedure
{   isolate_subproduct_changes requires the PF path container for the
{   element path to be initialized to an array of one on the first call.
{

  PROCEDURE isolate_subproduct_changes
    (    element_path_p: ^pft$path;
         new_pacs_catalog_path_p: ^pft$path;
         element_p {input} : ^rat$element;
         correction_process_record {input/output} : rat$correction_process_record;
     VAR active_element_count: rat$element_count;
     VAR corrections_generated: boolean;
     VAR corrections_carried_forward: boolean;
     VAR status: ost$status);


    VAR
      working_element_p: ^rat$element,
      first_element_down_p: ^rat$element,
      i: fst$number_of_path_elements,
      new_correction_generated: boolean,
      next_element_path_p: ^pft$path,
      next_level_active_element_count: rat$element_count,
      previous_correction_used: boolean;


    status.normal := TRUE;
    corrections_generated := FALSE;
    corrections_carried_forward := FALSE;
    working_element_p := element_p;
    active_element_count := 0;

{ Process the files and subcatalogs at the current catalog level.

    WHILE working_element_p <> NIL DO

      element_path_p^ [UPPERBOUND (element_path_p^)] := working_element_p^.name;

      IF working_element_p^.element_type = rac$file THEN

        isolate_file_changes (element_path_p, new_pacs_catalog_path_p, correction_process_record,
              working_element_p, new_correction_generated, previous_correction_used, status);

      ELSE {rac$catalog}

        IF working_element_p^.element_count = 0 THEN

          new_correction_generated := FALSE;
          previous_correction_used := FALSE;

        ELSE

          { Create a PF format path array that is 1 larger than the size of the
          { element path.  This array will be used to construct the PF paths for
          { the files and subcatalogs that reside in the next level catalog in the
          { element list.

          PUSH next_element_path_p: [1 .. UPPERBOUND (element_path_p^) + 1];
          FOR i := 1 TO UPPERBOUND (element_path_p^) DO
            next_element_path_p^ [i] := element_path_p^ [i];
          FOREND;

          { Process the next level catalog.

          first_element_down_p := #PTR (working_element_p^.first_element_down_p,
                correction_process_record.new_subproduct_info_pointers.subproduct_info_seq_p^);

          isolate_subproduct_changes (next_element_path_p, new_pacs_catalog_path_p, first_element_down_p,
                correction_process_record, next_level_active_element_count, new_correction_generated,
                previous_correction_used, status);

        IFEND;

      IFEND;
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      IF NOT (new_correction_generated OR previous_correction_used) THEN

        { The new PACS catalog doesn't contain this element, so element is defined as inactive
        { in the element list.

        working_element_p^.active_element := FALSE;
      ELSE
        active_element_count := active_element_count + 1;
      IFEND;

      corrections_generated := (corrections_generated OR new_correction_generated);
      corrections_carried_forward := (corrections_carried_forward OR previous_correction_used);

      working_element_p := #PTR (working_element_p^.next_element_across_p,
            correction_process_record.new_subproduct_info_pointers.subproduct_info_seq_p^);
    WHILEND;

  PROCEND isolate_subproduct_changes;

?? OLDTITLE ??
?? NEWTITLE := 'update_element_info', EJECT ??

{ PURPOSE:
{   This procedure traverses the compressed element list.  For every file in
{   the compressed element list, the element is located in the corresponding
{   new element list.  The non-directly dependent element information is
{   copied from the new element to the compressed element.
{
{ DESIGN:
{   Determining what files belong to the subproduct is accomplished by
{   traversing the element list for the subproduct.  The traverse is
{   performed using recursion and each call to UPDATE_ELEMENT_INFO
{   moves processing down to the next catalog level.
{
{ NOTES:
{

  PROCEDURE update_element_info
    (    element_path_p: ^pft$path;
         compressed_element_p {input/output} : ^rat$element;
         compressed_subproduct_info_ptrs {input/output} : rat$subproduct_info_pointers;
     VAR new_subproduct_info_ptrs: rat$subproduct_info_pointers;
     VAR status: ost$status);


    VAR
      working_compressed_element_p: ^rat$element,
      element_found: boolean,
      first_element_down_p: ^rat$element,
      i: fst$number_of_path_elements,
      new_element_p: ^rat$element,
      next_element_path_p: ^pft$path;


    status.normal := TRUE;
    working_compressed_element_p := compressed_element_p;

{ Process the files and subcatalogs at the current catalog level.

    WHILE working_compressed_element_p <> NIL DO

      element_path_p^ [UPPERBOUND (element_path_p^)] := working_compressed_element_p^.name;

      { Locate element info in new subproduct info sequence element list.

      new_element_p := new_subproduct_info_ptrs.element_list_p;
      rap$locate_element (element_path_p, 1 {path index} , new_subproduct_info_ptrs.subproduct_info_seq_p,
            new_element_p, element_found);

      { Copy the element info from the new element to the compressed element.
      copy_element_info (new_element_p, working_compressed_element_p);

      IF working_compressed_element_p^.element_type = rac$catalog THEN

        { Create a PF format path array that is 1 larger than the size of the
        { element path.  This array will be used to construct the PF paths for
        { the files and subcatalogs that reside in the next level catalog in the
        { element list.

        PUSH next_element_path_p: [1 .. UPPERBOUND (element_path_p^) + 1];
        FOR i := 1 TO UPPERBOUND (element_path_p^) DO
          next_element_path_p^ [i] := element_path_p^ [i];
        FOREND;

        { Process the next level catalog.

        first_element_down_p := #PTR (working_compressed_element_p^.first_element_down_p,
              compressed_subproduct_info_ptrs.subproduct_info_seq_p^);

        update_element_info (next_element_path_p, first_element_down_p, compressed_subproduct_info_ptrs,
              new_subproduct_info_ptrs, status);

      IFEND;
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      working_compressed_element_p := #PTR (working_compressed_element_p^.next_element_across_p,
            compressed_subproduct_info_ptrs.subproduct_info_seq_p^);
    WHILEND;

  PROCEND update_element_info;

?? OLDTITLE ??
?? NEWTITLE := 'use_previous_correction', EJECT ??

{ PURPOSE:
{   This procedure moves the file from the previous correction to the new
{   PACS catalog.
{
{ DESIGN:
{   Non-existing catalogs are created along the way.
{
{ NOTES:
{

  PROCEDURE use_previous_correction
    (    element_path_p: ^pft$path;
         new_pacs_catalog_path_p: ^pft$path;
         new_file_path: rat$path;
         previous_file_path: rat$path;
         previous_element_p : ^rat$element;
         element_p {output} : ^rat$element;
     VAR previous_correction_used: boolean;
     VAR status: ost$status);


    status.normal := TRUE;

    create_pacs_subcatalogs (new_pacs_catalog_path_p, element_path_p);

    fsp$copy_file (previous_file_path.path (1, previous_file_path.size),
          new_file_path.path (1, new_file_path.size), NIL, NIL, NIL, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    element_p^.pre_genc_contents_checksum := previous_element_p^.pre_genc_contents_checksum;
    element_p^.correction_base_contents_cksum := previous_element_p^.correction_base_contents_cksum;

    previous_correction_used := TRUE;

  PROCEND use_previous_correction;

?? OLDTITLE ??
?? NEWTITLE := 'write_compressed_sif', EJECT ??

{ PURPOSE:
{   This procedure compresses a new subproduct info sequence in memory and
{   writes it into the subproduct information file under the PACS catalog.
{   The compression removes inactive elements from the element list.
{
{ DESIGN:
{   A scratch sequence is created to hold a compressed subproduct
{   information sequence.  The element list section is created in the
{   compressed version of the subproduct info sequence by calling the same
{   interface that created the element list for DEFINE_SUBPRODUCT.
{
{   The relative pointer to the element list must be set in the subproduct
{   info header.
{
{   Certain element information stored in the new subproduct information
{   sequence is moved to the element list in the compressed subproduct
{   information sequence.
{
{ NOTES:
{

  PROCEDURE write_compressed_sif
    (    element_path_p: ^pft$path;
     VAR new_subproduct_info_ptrs {input} : rat$subproduct_info_pointers;
     VAR status: ost$status);


    VAR
      attributes_p: ^rat$subproduct_attributes,
      compressed_element_list_p: ^rat$element,
      compressed_subproduct_info_ptrs: rat$subproduct_info_pointers,
      fs_path: fst$path,
      ignore_cycle_reference: fst$cycle_reference,
      ignore_cycle_selector: clt$cycle_selector,
      ignore_open_position: fst$open_position,
      info_header_p: ^rat$subproduct_info_header,
      local_status: ost$status,
      number_of_path_elements: fst$number_of_path_elements,
      pacs_catalog_path: rat$path,
      pacs_catalog_path_p: ^pft$path,
      path_container_p: ^rat$path_container,
      psrs_answered_p: ^rat$psrs_answered,
      scratch_segment_pointer: amt$segment_pointer,
      sequence_descriptor_p: ^rat$sequence_descriptor,
      validation_errors: boolean,
      validation_selections: rat$validation_selections;


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

{ PURPOSE:
{   This procedure cleans up when an abort situation occurs within the
{   block structure.
{
{ DESIGN:
{   The function of this condition handler is to return the memory
{   scratch segment (used to contain the compressed subproduct info
{   sequence) when an abort condition arises.
{
{ 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 scratch_segment_pointer.sequence_pointer <> NIL THEN
        mmp$delete_scratch_segment (scratch_segment_pointer, ignore_status);
        scratch_segment_pointer.sequence_pointer := NIL;
      IFEND;

    PROCEND abort_handler;

?? OLDTITLE, EJECT ??


    status.normal := TRUE;
    scratch_segment_pointer.kind := amc$sequence_pointer;
    scratch_segment_pointer.sequence_pointer := NIL;
    pacs_catalog_path := new_subproduct_info_ptrs.attributes_p^.pacs_catalog_path;
    validation_errors := FALSE;

    osp$establish_block_exit_hndlr (^abort_handler);

  /main/
    BEGIN

      mmp$create_scratch_segment (amc$sequence_pointer, mmc$as_random, scratch_segment_pointer, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;
      compressed_subproduct_info_ptrs.subproduct_info_seq_p := scratch_segment_pointer.sequence_pointer;
      RESET compressed_subproduct_info_ptrs.subproduct_info_seq_p;

      { Copy the sequence descriptor, subproduct header and subproduct attributes from the new to
      { the compressed sequence.  Establish the compressed subproduct info pointers.

      NEXT sequence_descriptor_p IN compressed_subproduct_info_ptrs.subproduct_info_seq_p;
      sequence_descriptor_p^ := new_subproduct_info_ptrs.sequence_descriptor_p^;
      compressed_subproduct_info_ptrs.sequence_descriptor_p := sequence_descriptor_p;

      NEXT info_header_p IN compressed_subproduct_info_ptrs.subproduct_info_seq_p;
      info_header_p^ := new_subproduct_info_ptrs.info_header_p^;
      compressed_subproduct_info_ptrs.info_header_p := info_header_p;

      NEXT attributes_p IN compressed_subproduct_info_ptrs.subproduct_info_seq_p;
      attributes_p^ := new_subproduct_info_ptrs.attributes_p^;
      compressed_subproduct_info_ptrs.attributes_p := attributes_p;

      NEXT compressed_element_list_p IN compressed_subproduct_info_ptrs.subproduct_info_seq_p;
      compressed_subproduct_info_ptrs.element_list_p := compressed_element_list_p;

      pfp$convert_string_to_fs_path (pacs_catalog_path.path (1, pacs_catalog_path.size), fs_path,
            number_of_path_elements, ignore_cycle_reference, ignore_open_position, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      PUSH pacs_catalog_path_p: [1 .. number_of_path_elements];
      pfp$convert_fs_path_to_pf_path (fs_path, pacs_catalog_path_p, ignore_cycle_reference,
            ignore_cycle_selector, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      validation_selections := $rat$validation_selections [rac$loading_cycle_only, rac$no_rings_below_11,
            rac$no_permits];

      rap$create_element_list (^pacs_catalog_path.path (1, pacs_catalog_path.size), pacs_catalog_path_p^,
            validation_selections, TRUE {checksum_files} , validation_errors, compressed_subproduct_info_ptrs,
            status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      { The relative pointers in the info header for the attributes and the element list have not changed.
      { They do not need to be recalculated.

      { Copy the path container and the PSRs answered section from the new to
      { the compressed sequence (after the element list).

      NEXT path_container_p: [1 .. UPPERBOUND (new_subproduct_info_ptrs.path_container_p^)] IN
            compressed_subproduct_info_ptrs.subproduct_info_seq_p;
      path_container_p^ := new_subproduct_info_ptrs.path_container_p^;
      info_header_p^.path_container_p := #REL (path_container_p,
            compressed_subproduct_info_ptrs.subproduct_info_seq_p^);

      IF new_subproduct_info_ptrs.psrs_answered_p <> NIL THEN
        NEXT psrs_answered_p: [1 .. UPPERBOUND (new_subproduct_info_ptrs.psrs_answered_p^)] IN
              compressed_subproduct_info_ptrs.subproduct_info_seq_p;
        psrs_answered_p^ := new_subproduct_info_ptrs.psrs_answered_p^;
        info_header_p^.psrs_answered_p := #REL (psrs_answered_p,
              compressed_subproduct_info_ptrs.subproduct_info_seq_p^);
      IFEND;

      { Update the element information in the compressed element list using the new element list.

      update_element_info (element_path_p, compressed_element_list_p, compressed_subproduct_info_ptrs,
            new_subproduct_info_ptrs, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      rap$write_subproduct_info_file (pacs_catalog_path, compressed_subproduct_info_ptrs, status);

    END /main/;

    IF scratch_segment_pointer.sequence_pointer <> NIL THEN
      mmp$delete_scratch_segment (scratch_segment_pointer, local_status);
      scratch_segment_pointer.sequence_pointer := NIL;
      IF status.normal AND (NOT local_status.normal) THEN
        status := local_status;
      IFEND;
    IFEND;

    osp$disestablish_cond_handler;

  PROCEND write_compressed_sif;

MODEND ram$generate_correction_pacs;
