?? RIGHT := 110 ??
?? NEWTITLE := 'INSTALL_SOFTWARE Utility: RAP$VALIDATE_FOR_CORRECTION Interface.' ??
MODULE ram$validate_for_correction;
{ PURPOSE:
{   This module contains the interface and procedures that validate that
{   corrections can be installed.
{
{ DESIGN:
{
{   Factors influencing the correction process:
{
{   The correction process is driven by several factors, some of which
{   are controlled by the subproduct being corrected, some of which are
{   controlled by the environment the subproduct is being installed into
{   and some of which are controlled by the user.  The factors of primary
{   interest to this interface are:
{
{     Subproduct:
{        a) The installation scheme (cycle_based or version_based).
{           In a version based correction installation scheme, the corrected
{           files are written into a different catalog than the base level
{           of the subproduct.  This means files which did not need to be
{           corrected must be copied to the new version catalog from the base
{           level.  Files/catalogs which are not present in the correction
{           because they don't require correction were marked as inactive
{           in the element list (by GENERATE_CORRECTION) whereas those which
{           will require correction were marked as active.
{           This also influences processing of the correction base files as
{           described below.
{        b) The correction format of each file (object library, source library,
{           or replacement).  An object library correction consists of a patch
{           which when applied against the base(release) version of the file
{           will produce the corrected file.  When the installation scheme
{           is cycle_based, the corrected file would overwrite the correction
{           base so we must save it in a catalog called
{           the correction base catalog for use in installing future
{           corrections.  For version based, the correction base file need not
{           be copied to the correction base catalog because the newly applied
{           correction is installed to a new version catalog.
{     Environment:
{        a) The existance (or not) of previous corrections to this subproduct.
{           When possible, we will not re-correct a file if the correction
{           has already been installed on the system as part of a previous
{           correction installation.  Also, if an object library has been
{           previously corrected, we know the correction base for the file
{           is in the correction bases catalog (for cycle based corrections).
{           If an object library has not been corrected, the correction base
{           will be where the file was originally installed (base level
{           catalog).
{     User:
{        a) How the user selects the subproduct correction to be installed
{           (by name specifically, by licensed product or by group).
{           When the user selects a subproduct by name, every correction
{           to every file in the subproduct will be installed, no
{           previously installed corrections will be used. When referenced
{           by licensed product or group, previously installed corrections
{           will be used if possible to speed up the installation of the
{           new correction.
{
{   By the time this interface is invoked, we know which subproduct's the
{   user wishes to correct.  This interface will consider
{   the above factors in determining how the correction will be installed
{   and in validating that all files which are required for the installation
{   are available.  Information about the processing requirements of each
{   file will be stored in its element record for later use during the actual
{   application of the corrections.
{
{   The significance of these factors is shown in the following "algorithm"
{   which describes the correction process to a file in a subproduct. These
{   show the combined logic of validation for correction and installation of
{   corrections.
{
{   IF <installation scheme is version_based> THEN
{     IF <not installed by subproduct name and correction format is object
{        and correction was installed previously> THEN
{       <move the installed correction to the loading cycle of the new
{        version catalog.>
{       <validate the installed correction to ensure it is not corrupted.>
{       <delete correction from loading cycle.>
{     ELSEIF <element is inactive> THEN
{       <move base level file forward to loading cycle of the new version
{        catalog.>
{     ELSEIF <file format is object library> THEN
{       <correct as for cycle based>
{     ELSE {file format is source library or replacement}
{       <correct as for cycle based>
{     IFEND
{   ELSE {installation scheme is cycle based}
{     IF <not installed by subproduct name and correction was previously
{        installed> THEN
{       <delete the correction from loading cycle>
{       <validate that file is already installed>
{     ELSEIF <file format is object library> THEN
{       <put base (release) version of file in correction bases catalog
{        if not already there>
{       <apply correction placing corrected file in staging cycle>
{       <delete the correction file and shift corrected file back to
{        loading cycle where it is expected by during staging>
{     ELSE {file format is source library or replacement}
{       {no processing needed}
{     IFEND
{   IFEND
{   The compiled module resides in RAF$LIBRARY.
{
{ NOTES:
{

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc rac$control_job_identifier
*copyc rae$install_software_cc
*copyc ost$status
*copyc rat$element_paths
*copyc rat$subproduct_info_types
?? POP ??
*copyc amp$get_file_attributes
*copyc amp$get_segment_pointer
*copyc clp$trimmed_string_size
*copyc fsp$close_file
*copyc fsp$open_file
*copyc mmp$create_scratch_segment
*copyc mmp$delete_scratch_segment
*copyc ofp$receive_operator_response
*copyc ofp$send_operator_message
*copyc osp$append_status_file
*copyc osp$append_status_parameter
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc osp$generate_log_message
*copyc osp$set_status_abnormal
*copyc pmp$get_unique_name
*copyc rap$assemble_installation_path
*copyc rap$convert_path_to_pf_format
*copyc rap$convert_path_to_str
*copyc rap$init_processing_seq
*copyc rap$locate_element
*copyc rap$locate_directory_record

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

{   To validate the subproducts which are to be corrected, a linked list
{   of subproduct validation lists is created.  All the subproducts in a
{   subproduct validation list have the same subproduct state, ie they
{   have been previously corrected or they have never been corrected.
{   The header node for each list contains the subproduct state plus
{   pointers to the first and last nodes of the subproduct list and to
{   the next subproduct list.  If the subproducts have been previously
{   corrected, then the header also contains the name of the packing list
{   that the subproducts are from.  This packing list is used in
{   determining what file corrections have already been installed for
{   each subproduct.
{
{   Each node of a subproduct list contains the subproduct name,
{   information to access the directory entry for the subproduct, an
{   index to access its subproduct processing record, and for
{   subproduct's which have been previously corrected, an index into the
{   packing list for this subproducts, subproduct list.
{
{   The validation list is kept in a scratch sequence created specifically
{   to contain the list.

  TYPE

    rat#subproduct_state = (rac#never_corrected, rac#previously_corrected),
    rat#validation_list_header = record
      first_subproduct_p: ^rat#subproduct_info_record,
      last_subproduct_p: ^rat#subproduct_info_record,
      next_validation_list_p: ^rat#validation_list_header,
      packing_list_name: ost$name,
      subproduct_state: rat#subproduct_state,
    recend,
    rat#subproduct_info_record = record
      subproduct_name: rat$subproduct_name,
      directory_record_p: ^rat$directory_record,
      processing_records_index: integer,
      next_subproduct_p: ^rat#subproduct_info_record,
      case subproduct_state: rat#subproduct_state of
      = rac#previously_corrected =
        packing_list_index: rat$subproduct_count,
      = rac#never_corrected =
      casend,
    recend;

{   The following record is used during validation of a subproduct.  It keeps
{   all non-changing input information in one parameter.

  TYPE
    rat#validation_info_record = record
      active_subproduct_info_seq_p: ^rat$subproduct_info_sequence,
      active_element_list_p: ^rat$element,
      active_path_index: integer,
      allowed_to_use_previous_corrs: boolean,
      correction_installation_scheme: rat$installation_scheme,
      subproduct_info_seq_p: ^rat$subproduct_info_sequence,
      subproduct_name: rat$subproduct_name,
      subproduct_state: rat#subproduct_state,
    recend;

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

{ PURPOSE:
{   This interface validates that all correction base files are present and
{   establishes the correction_directives for the elements of each
{   subproduct to be corrected.
{
{ DESIGN:
{   Create the subproduct validation lists.  This allows processing of
{   subproducts whose active levels are from the same packing list in the
{   most efficient manner by only requiring one access to each packing list.
{   (Subproducts which have never been corrected are also grouped into
{   one subproduct validation list.
{
{   After the validation lists are created, each list is processed to validate
{   that the corrections in each subproduct can in fact be installed.  The
{   validation process updates the element records of each subproduct to
{   direct the correction process during the correct products step.
{
{   Validation errors for one subproduct list or subproduct in a subproduct
{   list will not prevent validation of other subproducts.
{   All validation errors are reported to the job log.
{ NOTES:
{   1.  The validation lists are kept in a scratch memory segment.

  PROCEDURE [XDCL] rap$validate_for_correction
    (    directory_pointers: rat$idb_directory_pointers;
     VAR installation_control_record: rat$installation_control_record;
     VAR status: ost$status);

    VAR
      current_subproduct_header_p: ^rat#validation_list_header,
      errs_processing_validation_list: boolean,
      local_status: ost$status,
      validation_errors: boolean,
      validation_lists_segment_ptr: amt$segment_pointer,
      validation_lists_p: ^rat#validation_list_header,
      validation_lists_seq_p: ^SEQ ( * );


?? 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
{   validation list scratch segment.

    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 validation_lists_segment_ptr.sequence_pointer <> NIL THEN
        mmp$delete_scratch_segment (validation_lists_segment_ptr, ignore_status);
        validation_lists_segment_ptr.sequence_pointer := NIL;
      IFEND;

    PROCEND abort_handler;
?? OLDTITLE, EJECT ??

    status.normal := TRUE;

    validation_lists_p := NIL;
    validation_lists_segment_ptr.kind := amc$sequence_pointer;
    validation_lists_segment_ptr.sequence_pointer := NIL;

    osp$establish_block_exit_hndlr (^abort_handler);

  /main/
    BEGIN

      mmp$create_scratch_segment (amc$sequence_pointer, mmc$as_random, validation_lists_segment_ptr,
            status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      validation_lists_seq_p := validation_lists_segment_ptr.sequence_pointer;

      get_subproduct_validation_lists (installation_control_record.subproduct_processing_records_p,
            directory_pointers, validation_lists_p, validation_lists_seq_p, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      current_subproduct_header_p := validation_lists_p;
      validation_errors := FALSE;

      WHILE current_subproduct_header_p <> NIL DO
        process_subp_validation_list (current_subproduct_header_p, installation_control_record,
              errs_processing_validation_list, status);
        IF NOT status.normal THEN
          EXIT /main/;
        IFEND;
        validation_errors := (validation_errors OR errs_processing_validation_list);
        current_subproduct_header_p := current_subproduct_header_p^.next_validation_list_p;
      WHILEND;

    END /main/;

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

    osp$disestablish_cond_handler;

    IF status.normal AND validation_errors THEN
      osp$set_status_abnormal ('RA', rae$correction_validation_errs, '', status);
    IFEND;

  PROCEND rap$validate_for_correction;

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

{ PURPOSE:
{   This procedure adds information about a subproduct to a validation list.
{   If no validation list exists for this subproduct, a new validation list
{   is created and added to the list of validation lists.
{
{ DESIGN:
{   Attempt to locate the proper validation list for the subproduct based upon
{   the subproduct state and if appropriate, packing list name.
{   If the needed validation list is found, add this subproduct to it,
{   initializing the fields for the subproduct.
{
{   If the validation list cannot be found, a new one is created
{   and added to the linked list of validation lists.
{ NOTES:


  PROCEDURE add_to_validation_list
    (    subproduct_state: rat#subproduct_state;
         subproduct_name: rat$subproduct_name;
         processing_records_index: integer;
         directory_record_p: ^rat$directory_record;
     VAR validation_lists_p: ^rat#validation_list_header;
     VAR validation_lists_seq_p: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      current_validation_list_p: ^rat#validation_list_header,
      new_subproduct_validation_rec_p: ^rat#subproduct_info_record;

    status.normal := TRUE;

    IF validation_lists_p = NIL THEN
      { No validation lists have been initialized.  A validation list is initialized by
      { creating an validation list header for the subproduct state/packing list used
      { by this subproduct.

      NEXT current_validation_list_p IN validation_lists_seq_p;
      IF current_validation_list_p = NIL THEN
        osp$set_status_abnormal ('RA', rae$accessed_beyond_segment_eoi, 'VALIDATION LIST', status);
        osp$append_status_parameter (osc$status_parameter_delimiter, 'VALIDATION LIST HEADER', status);
        RETURN;
      IFEND;

      validation_lists_p := current_validation_list_p;

      current_validation_list_p^.subproduct_state := subproduct_state;
      IF subproduct_state = rac#previously_corrected THEN
        current_validation_list_p^.packing_list_name := directory_record_p^.active_information.packing_list;
      ELSE
        current_validation_list_p^.packing_list_name := osc$null_name;
      IFEND;
      current_validation_list_p^.first_subproduct_p := NIL;
      current_validation_list_p^.last_subproduct_p := NIL;
      current_validation_list_p^.next_validation_list_p := NIL;

    ELSE {there is at least one existing validation list}
      { Locate the validation list for the desired subproduct state/packing list.
      { Note that the search will stop with current_validation_list_p pointing
      { to the last validation list.

      current_validation_list_p := validation_lists_p;
      IF subproduct_state = rac#never_corrected THEN
        WHILE (current_validation_list_p^.subproduct_state <> rac#never_corrected) AND
              (current_validation_list_p^.next_validation_list_p <> NIL) DO
          current_validation_list_p := current_validation_list_p^.next_validation_list_p;
        WHILEND;
      ELSE { Search based upon packing list.}
        WHILE (current_validation_list_p^.packing_list_name <>
              directory_record_p^.active_information.packing_list) AND
              (current_validation_list_p^.next_validation_list_p <> NIL) DO
          current_validation_list_p := current_validation_list_p^.next_validation_list_p;
        WHILEND;
      IFEND;

      IF ((subproduct_state = rac#never_corrected) AND (current_validation_list_p^.subproduct_state <>
            subproduct_state)) OR ((subproduct_state = rac#previously_corrected) AND
            (current_validation_list_p^.packing_list_name <> directory_record_p^.active_information.
            packing_list)) THEN
        { We did run to the end of the list without finding the correct validation
        { list.  A new validation list is initialized and linked to
        { the last validation list.

        NEXT current_validation_list_p^.next_validation_list_p IN validation_lists_seq_p;
        IF current_validation_list_p = NIL THEN
          osp$set_status_abnormal ('RA', rae$accessed_beyond_segment_eoi, 'VALIDATION LIST', status);
          osp$append_status_parameter (osc$status_parameter_delimiter, 'VALIDATION LIST HEADER', status);
          RETURN;
        IFEND;

        current_validation_list_p := current_validation_list_p^.next_validation_list_p;

        current_validation_list_p^.subproduct_state := subproduct_state;
        IF subproduct_state = rac#previously_corrected THEN
          current_validation_list_p^.packing_list_name := directory_record_p^.active_information.packing_list;
        ELSE
          current_validation_list_p^.packing_list_name := osc$null_name;
        IFEND;
        current_validation_list_p^.first_subproduct_p := NIL;
        current_validation_list_p^.last_subproduct_p := NIL;
        current_validation_list_p^.next_validation_list_p := NIL;

      IFEND;
    IFEND;

    { Add the subproduct name to end of the current activation list.

    NEXT new_subproduct_validation_rec_p IN validation_lists_seq_p;
    IF new_subproduct_validation_rec_p = NIL THEN
      osp$set_status_abnormal ('RA', rae$accessed_beyond_segment_eoi, 'VALIDATION LIST', status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'SUBPRODUCT VALIDATION RECORD', status);
      RETURN;
    IFEND;

    IF current_validation_list_p^.first_subproduct_p = NIL THEN
      { This is the first name recorded.
      current_validation_list_p^.first_subproduct_p := new_subproduct_validation_rec_p;
    ELSE
      current_validation_list_p^.last_subproduct_p^.next_subproduct_p := new_subproduct_validation_rec_p;
    IFEND;

    current_validation_list_p^.last_subproduct_p := new_subproduct_validation_rec_p;
    current_validation_list_p^.last_subproduct_p^.subproduct_name := subproduct_name;
    current_validation_list_p^.last_subproduct_p^.directory_record_p := directory_record_p;
    current_validation_list_p^.last_subproduct_p^.processing_records_index := processing_records_index;
    current_validation_list_p^.last_subproduct_p^.subproduct_state := subproduct_state;
    IF subproduct_state = rac#previously_corrected THEN
      current_validation_list_p^.last_subproduct_p^.packing_list_index :=
            directory_record_p^.active_information.packing_list_index;
    IFEND;
    current_validation_list_p^.last_subproduct_p^.next_subproduct_p := NIL;

  PROCEND add_to_validation_list;

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

{ PURPOSE:
{   This procedure checks a previous correction to determine if it can be
{   used to avoid installing the current correction.  If the checksum's
{   match, and we want to use it, then we ensure the file exists.
{
{ DESIGN:
{   If the checksum's in the element lists match, then the previous
{   correction can be used.  It is only used however, if the installation
{   scheme is cycle based, or for a version based installation scheme, if
{   the correction is to an object library.  The reason for
{   selectivity in version based corrections is that it would take more
{   processing to use a previous correction to a source library or
{   replacement file than to use the correction which was loaded into the
{   loading cycle.
{
{   If based on the above, we want to use the previous correction, we make
{   sure the file is present and issue an error message if it's not.
{
{   If we use the previous correction and the installation scheme is
{   cycle based, then the element is made inactive since no further
{   processing is needed.
{ NOTES:


  PROCEDURE check_previous_correction
    (    element_paths: rat$element_paths;
         validation_info_record: rat#validation_info_record;
         previous_correction_element_p: ^rat$element;
         element_p {input, output} : ^rat$element;
     VAR previous_correction_usable: boolean;
     VAR status: ost$status);

    VAR
      display_status: ost$status,
      ignore_status: ost$status,
      previous_correction_file_exists: boolean;

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

    IF (previous_correction_element_p^.pre_genc_contents_checksum = element_p^.pre_genc_contents_checksum)
          THEN
      IF (validation_info_record.correction_installation_scheme = rac$cycle_based) THEN

        { We know file already exists since we checked the base file in VALIDATE_FILE.
        element_p^.active_element := FALSE;
        previous_correction_usable := TRUE;

      ELSE {version based}

        IF (element_p^.correction_format = rac$object_library) THEN
          verify_file_exists (element_paths [rac$active_level_path], previous_correction_file_exists, status);
          IF NOT status.normal THEN
            RETURN;
          IFEND;
          IF previous_correction_file_exists THEN
            previous_correction_usable := TRUE;
          ELSE
            log_missing_file_message (rae$prev_version_corr_missing, element_paths [rac$active_level_path],
                  element_paths [rac$installation_catalog_path], validation_info_record.subproduct_name,
                  ignore_status);
          IFEND;
        IFEND;
      IFEND;
    IFEND;

    IF previous_correction_usable THEN
       element_p^.correction_directives := $rat$correction_directives [rac$use_previous_correction];
    IFEND;

  PROCEND check_previous_correction;
?? OLDTITLE, NEWTITLE := 'establish_subproduct_paths', EJECT ??

{ PURPOSE:
{   This procedure establishes various paths needed for installing the
{   subproduct.
{
{ DESIGN:
{   Use the directory record plus the active subproduct pointers (if
{   available) to determine the paths.  The path's and relative pointer's
{   to them are stored in the processing sequence.  An array of absolute
{   pointers for the paths is returned to the caller.
{ NOTES:
{   If the ACTIVE_SUBPRODUCT_INFO_PTRS.ATTRIBUTES_P is NIL, then
{   there is no active level of the subproduct.

  PROCEDURE establish_subproduct_paths
    (    directory_record_p: ^rat$directory_record;
         active_subproduct_info_ptrs: rat$subproduct_info_pointers;
         default_correction_base_catalog: rat$path;
     VAR subproduct_processing_record: rat$subp_processing_record;
     VAR subproduct_paths: rat$element_paths;
     VAR processing_sequence_p: ^rat$processing_sequence;
     VAR status: ost$status);


    VAR
      correction_base_catalog: rat$path,
      temp_system_catalog: rat$path;

    status.normal := TRUE;

    subproduct_paths [rac$installation_catalog_path] := subproduct_processing_record.installation_catalog_p;

    { Assemble path for the correction bases catalog for the subproduct.

    STRINGREP (correction_base_catalog.path, correction_base_catalog.size,
          default_correction_base_catalog.path (1, default_correction_base_catalog.size), '.',
          directory_record_p^.subproduct (1, clp$trimmed_string_size (directory_record_p^.subproduct)),
          '.', directory_record_p^.corrective_base_information.
          subproduct_level (1, clp$trimmed_string_size (directory_record_p^.corrective_base_information.
          subproduct_level)));
    rap$convert_path_to_pf_format (correction_base_catalog, subproduct_paths [rac$correction_base_cat_path],
          processing_sequence_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    subproduct_processing_record.correction_base_catalog_rel_p :=
          #REL (subproduct_paths [rac$correction_base_cat_path], processing_sequence_p^);

    { Get path for the base level of the subproduct.

    rap$convert_path_to_pf_format (directory_record_p^.base_level_installation_catalog,
          subproduct_paths [rac$base_level_path], processing_sequence_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    subproduct_processing_record.base_level_catalog_rel_p :=
          #REL (subproduct_paths [rac$base_level_path], processing_sequence_p^);

    { Get path for the active level of the subproduct.  This only occurs if
    { the active level is different than the base level.

    IF active_subproduct_info_ptrs.attributes_p <> NIL THEN
      temp_system_catalog := directory_record_p^.base_level_installation_catalog;
      temp_system_catalog.size := directory_record_p^.system_catalog_path_index;
      rap$assemble_installation_path (temp_system_catalog, active_subproduct_info_ptrs, rac$installation_path,
            subproduct_paths [rac$active_level_path], processing_sequence_p, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      subproduct_processing_record.active_level_catalog_rel_p :=
            #REL (subproduct_paths [rac$active_level_path], processing_sequence_p^);
    ELSE
      subproduct_processing_record.active_level_catalog_rel_p := NIL;
      subproduct_paths [rac$active_level_path] := NIL;
    IFEND;

  PROCEND establish_subproduct_paths;

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

{ PURPOSE:
{   This procedure builds the correction validation lists.
{
{ DESIGN:
{   Go through the subproduct processing records in the installation control
{   record and process each subproduct that has been selected.
{
{   Locate the subproduct's entry in the IDB directory.
{   1.  If the directory indicates that the active and base levels are
{       different, then a previous correction has been installed for this
{       subproduct.  Add this subproduct to the validation list for the
{       packing list of the active level.
{   2.  If the directory indicates that the active level is the same as the
{       base level for the subproduct, then no correction has ever been
{       applied to this subproduct.  This means that every correction in
{       this subproduct must be installed.  Add this subproduct to the
{       validation list for subproducts which have never been corrected.
{ NOTES:
{   If a subproduct has selected, but its correction_base_sif_identifier
{   is null, then the correction was created with DEFINE_SUBPRODUCT
{   and therefore only performs file replacement.  In this case,
{   no validation is necessary, and we will remove the correct_files_task
{   from the subproduct's task list.

  PROCEDURE get_subproduct_validation_lists
    (    subproduct_processing_records_p: ^rat$subp_processing_records;
         directory_pointers: rat$idb_directory_pointers;
     VAR validation_lists_p: ^rat#validation_list_header;
     VAR validation_lists_seq_p: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      directory_record_p: ^rat$directory_record,
      subproduct_index: rat$subproduct_count,
      subproduct_state: rat#subproduct_state;

    status.normal := TRUE;

    FOR subproduct_index := 1 TO UPPERBOUND (subproduct_processing_records_p^) DO

      IF (rac$correct_files_task IN subproduct_processing_records_p^ [subproduct_index].task_set) THEN

        IF (subproduct_processing_records_p^ [subproduct_index].subproduct_info_pointers.attributes_p^.
              correction_base_sif_identifier = osc$null_name) THEN
          subproduct_processing_records_p^ [subproduct_index].task_set :=
                subproduct_processing_records_p^ [subproduct_index].task_set -
                $rat$task_selections [rac$correct_files_task];

        ELSE

          rap$locate_directory_record (subproduct_processing_records_p^ [subproduct_index].
                subproduct_info_pointers.attributes_p^.name, subproduct_processing_records_p^ [
                subproduct_index].subproduct_info_pointers.attributes_p^.licensed_product, directory_pointers,
                directory_record_p);
          IF directory_record_p^.active_information.sif_identifier =
                directory_record_p^.corrective_base_information.sif_identifier THEN
            subproduct_state := rac#never_corrected;
          ELSE
            subproduct_state := rac#previously_corrected;
          IFEND;

          add_to_validation_list (subproduct_state, subproduct_processing_records_p^ [subproduct_index].
                subproduct_info_pointers.attributes_p^.name, subproduct_index, directory_record_p,
                validation_lists_p, validation_lists_seq_p, status);
          IF NOT status.normal THEN
            RETURN;
          IFEND

        IFEND;

      IFEND;

    FOREND;

  PROCEND get_subproduct_validation_lists;

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

{ PURPOSE:
{   This interface initializes the record of information needed to drive
{   the validation of a subproduct.
{
{ DESIGN:
{
{ NOTES:
{   If the ACTIVE_SUBPRODUCT_INFO_PTRS.ATTRIBUTES_P is NIL, then
{   there is no active level of the subproduct.
{
{   When calculating the active_path_index (how many catalog elements
{   to skip over during locate_element), we must add 1 to the
{   the number of elements in the active level catalog in order to
{   begin the search in the active level catalog, rather than at
{   the same level as the active level catalog.
{
{   If a subproduct was selected by the user by subproduct name
{   or the licensed product name and subproduct name match,
{   then we will not use previous corrections when correcting
{   the subproduct.  The need to check LP=SP is done
{   because validate_for_installation indicates the product
{   reference is licensed product, not subproduct like it
{   probably should.

  PROCEDURE init_validation_info_record
    (    active_subproduct_info_ptrs: rat$subproduct_info_pointers;
         active_level_path_p: ^pft$path;
         subproduct_processing_record: rat$subp_processing_record;
         subproduct_state: rat#subproduct_state;
     VAR validation_info_record: rat#validation_info_record);

    IF active_subproduct_info_ptrs.attributes_p <> NIL THEN
      validation_info_record.active_subproduct_info_seq_p :=
            active_subproduct_info_ptrs.subproduct_info_seq_p;
      validation_info_record.active_element_list_p := active_subproduct_info_ptrs.element_list_p;
      validation_info_record.active_path_index := UPPERBOUND (active_level_path_p^) + 1;
      IF ((subproduct_processing_record.product_reference = rac$subproduct) OR
         ((subproduct_processing_record.product_reference = rac$licensed_product) AND
         (subproduct_processing_record.subproduct_info_pointers.attributes_p^.licensed_product =
         subproduct_processing_record.subproduct_info_pointers.attributes_p^.name)) ) THEN
        validation_info_record.allowed_to_use_previous_corrs := FALSE;
      ELSE
        validation_info_record.allowed_to_use_previous_corrs := TRUE;
      IFEND;
    ELSE
      validation_info_record.active_subproduct_info_seq_p := NIL;
      validation_info_record.active_element_list_p := NIL;
      validation_info_record.active_path_index := 0;
      validation_info_record.allowed_to_use_previous_corrs := FALSE;
    IFEND;

    validation_info_record.correction_installation_scheme :=
          subproduct_processing_record.subproduct_info_pointers.attributes_p^.installation_scheme;
    validation_info_record.subproduct_info_seq_p := subproduct_processing_record.subproduct_info_pointers.
          subproduct_info_seq_p;
    validation_info_record.subproduct_name := subproduct_processing_record.subproduct_info_pointers.
          attributes_p^.name;
    validation_info_record.subproduct_state := subproduct_state;

  PROCEND init_validation_info_record;

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

{ PURPOSE:
{   This interface locates the correction base for a correction,
{   verifies that the file exists and updates the correction_directives for
{   the file accordingly.
{
{ DESIGN:
{   Use the input parameters to determine where the correction base file
{   should be located and update the correction directives for the file
{   accordingly.  If the file does not exist, display a status message to
{   the job log and return indicating that validation errors occurred.
{
{   Correction bases are located as follows:
{   1. For a version based subproduct, in the base version catalog.
{   2. For cycle based subproduct:
{      a. If the file has been previously corrected, in the correction
{         bases catalog.
{      b. If the file has never been corrected, in the base level catalog.
{      c. If the subproduct has been corrected, but we couldn't get the
{         previous correction info (because of problems accessing the
{         packing list in PROCESS_SUBP_VALIDATION_LIST), then we will use
{         a file in the correction bases catalog as the base if its
{         there, otherwise we will use the file in the base level
{         catalog.
{
  PROCEDURE locate_correction_base
    (    element_paths: rat$element_paths;
         validation_info_record: rat#validation_info_record;
         file_previously_corrected: boolean;
         element_p {input, output} : ^rat$element;
     VAR validation_error: boolean;
     VAR status: ost$status);

    VAR
      file_exists: boolean,
      ignore_status: ost$status;

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

    IF validation_info_record.correction_installation_scheme = rac$version_based THEN

      { We know file already exists.  This was checked in VALIDATE_FILE.
      element_p^.correction_directives := $rat$correction_directives [rac$use_base_level_catalog];

    ELSE {cycle based correction}

      IF file_previously_corrected THEN

        verify_file_exists (element_paths [rac$correction_base_cat_path], file_exists, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        IF file_exists THEN
          element_p^.correction_directives := $rat$correction_directives [rac$use_correction_base_catalog];
        ELSE
          log_missing_file_message (rae$corr_base_cat_file_missing,
                element_paths [rac$correction_base_cat_path], element_paths [rac$installation_catalog_path],
                validation_info_record.subproduct_name, ignore_status);
          validation_error := TRUE;
          RETURN;
        IFEND;

      ELSEIF (validation_info_record.subproduct_state = rac#never_corrected) OR
            ((validation_info_record.subproduct_state = rac#previously_corrected) AND
            (validation_info_record.active_subproduct_info_seq_p <> NIL)) THEN

        { We know file already exists.  This was checked in VALIDATE_FILE.
        element_p^.correction_directives := $rat$correction_directives [rac$use_base_level_catalog];

      ELSE {Subproduct previously corrected but active level subproduct info not available.}

        { See if a file exists in correction bases catalog.
        verify_file_exists (element_paths [rac$correction_base_cat_path], file_exists, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        IF file_exists THEN
          element_p^.correction_directives := $rat$correction_directives [rac$use_correction_base_catalog];
        ELSE
          element_p^.correction_directives := $rat$correction_directives [rac$use_base_level_catalog];
        IFEND;

      IFEND;

    IFEND;

  PROCEND locate_correction_base;

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

{ PURPOSE:
{   This procedure displays the specified status message for
{   a missing file to the $job_log.
{
{ DESIGN:
{   Convert the PFT$PATH's to strings and log the status message.
{
{ NOTES:

  PROCEDURE log_missing_file_message
    (    display_status: ost$status_condition_code;
         first_pf_path_p: ^pft$path;
         second_pf_path_p: ^pft$path;
         subproduct_name: rat$subproduct_name;
     VAR status: ost$status);

    VAR
      file_string: rat$path,
      working_status: ost$status;

    status.normal := TRUE;

    osp$set_status_abnormal ('RA', display_status, '', working_status);

    IF first_pf_path_p <> NIL THEN
      rap$convert_path_to_str (first_pf_path_p^, file_string);
      osp$append_status_file (osc$status_parameter_delimiter, file_string.path (1, file_string.size),
            working_status);
    IFEND;

    IF second_pf_path_p <> NIL THEN
      rap$convert_path_to_str (second_pf_path_p^, file_string);
      osp$append_status_file (osc$status_parameter_delimiter, file_string.path (1, file_string.size),
            working_status);
    IFEND;

    osp$append_status_parameter (osc$status_parameter_delimiter, subproduct_name, working_status);
    osp$generate_log_message ($pmt$ascii_logset [pmc$job_log], working_status, status);

  PROCEND log_missing_file_message;

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

{ PURPOSE:
{   This procedure processes the subproducts in a subproduct validation list.
{
{ DESIGN:
{   Use information in the validation list header record to determine if
{   a packing list is needed to process the subproducts.  If so, use an
{   installation control record (named previous_corr_packing_list_rec)
{   and associated sequence to access information about the previously
{   corrected subproducts.  If there is an error during initialization of
{   the sequence, we will not be able to use previous correction
{   information in processing the subproducts.  Log this fact and proceed
{   with validating each subproduct in the subproduct validation list.
{
{   Note: If a subproduct is being recorrected, the active level may in
{   in fact be the same as the level being installed.  In that case,
{   we will not open the packing list but use the current
{   packing list for previous correction information.
{
{   For each member of the list, establish the subproduct paths which will be
{   needed during installation and store them in the processing sequence for
{   the current installation.  (NOT the processing sequence for previously
{   corrected subproducts.)  Initialize a record to contain all information
{   necessary to validate the subproduct and call a procedure to traverse the
{   element list for the subproduct, validating each element and its
{   correction processing requirements.
{
{   During the initialization of the validation record, it is determined
{   if the previous corrections can be used to speed up the application
{   of the correction.  The corrections cannot be used if the user
{   specified the subproduct by name on the INSTALL_CORRECTION command.
{
{ NOTES:
{   It is possible, although very unlikely, that a packing list used for
{   installing the active level of a subproduct gets reloaded at the site.
{   Since we do not have a unique 'packing_list_id' like we have a unique
{   subproduct identifier, we cannot determine this fact upon accessing
{   the packing list.  It can only be determined while the subproducts
{   with the validation list for that packing list are being processed.
{   An even more unlikely case is that some of the needed subproducts
{   are in the packing list, and that others are not.  This code handles
{   either case, using the information in the packing list if its there.
{   In the future, a packing_list_unique_id should be added to each packing
{   list and to the idb directory.

  PROCEDURE process_subp_validation_list
    (    validation_list_header_p: ^rat#validation_list_header;
     VAR installation_control_record: rat$installation_control_record;
     VAR validation_errors: boolean;
     VAR status: ost$status);

    CONST
      ignore_cmd_compatible_type = rac$correction,
      ignore_installation_command = rac$install_correction,
      ignore_save_previous_cycles = FALSE;

    VAR
      current_subproduct_p: ^rat#subproduct_info_record,
      ignore_status: ost$status,
      local_status: ost$status,
      operator_message: string (256),
      operator_message_length : integer,
      packing_list_fid: amt$file_identifier,
      packing_list_open: boolean,
      previous_corr_info_available: boolean,
      previous_corr_packing_list_rec: rat$installation_control_record,
      previous_corr_segment_pointer: amt$segment_pointer,
      previous_corr_subp_info_ptrs: rat$subproduct_info_pointers,
      response_from_operator: ost$string,
      subproduct_paths: rat$element_paths,
      subproduct_validation_errors: boolean,
      validation_info_record: rat#validation_info_record;

?? 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 close the packing list
{   and return the previous correction processing sequence.

    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 packing_list_open THEN
        fsp$close_file (packing_list_fid, ignore_status);
        packing_list_open := FALSE;
      IFEND;

      IF previous_corr_segment_pointer.sequence_pointer <> NIL THEN
        mmp$delete_scratch_segment (previous_corr_segment_pointer, ignore_status);
        previous_corr_segment_pointer.sequence_pointer := NIL;
      IFEND;
    PROCEND abort_handler;
?? OLDTITLE, EJECT ??

    status.normal := TRUE;

    validation_errors := FALSE;
    packing_list_open := FALSE;

    previous_corr_packing_list_rec.job_identifier := rac$control_job_identifier;
    previous_corr_segment_pointer.kind := amc$sequence_pointer;
    previous_corr_segment_pointer.sequence_pointer := NIL;

    osp$establish_block_exit_hndlr (^abort_handler);

  /main/
    BEGIN

      previous_corr_info_available := FALSE;
      IF validation_list_header_p^.subproduct_state = rac#previously_corrected THEN
        IF validation_list_header_p^.packing_list_name = installation_control_record.processing_header_p^.
                packing_list_name THEN
           { The subproducts are referencing the current packing list, copy current ICR for validation.
           previous_corr_packing_list_rec := installation_control_record;
           previous_corr_info_available := TRUE;
        ELSE {Must access other packing list.}
          rap$init_processing_seq (validation_list_header_p^.packing_list_name, ignore_save_previous_cycles,
                ignore_installation_command, ignore_cmd_compatible_type,
                installation_control_record.processing_header_p^.installation_defaults,
                previous_corr_packing_list_rec, previous_corr_segment_pointer, packing_list_fid,
                packing_list_open, local_status);
          IF local_status.normal THEN
            previous_corr_info_available := TRUE;
          ELSE
            osp$generate_log_message ($pmt$ascii_logset [pmc$job_log], local_status, ignore_status);
            osp$set_status_abnormal ('RA', rae$previous_corr_packlist_gone, '', local_status);
            osp$generate_log_message ($pmt$ascii_logset [pmc$job_log], local_status, ignore_status);
            local_status.normal := TRUE;
            previous_corr_info_available := FALSE;
          IFEND;
        IFEND;
      IFEND;

      current_subproduct_p := validation_list_header_p^.first_subproduct_p;
      WHILE current_subproduct_p <> NIL DO

        IF previous_corr_info_available THEN
          { Validate that the sif id of the active subproduct matches the
          { sif id for the subproduct pointed to in the packing list.
          IF (current_subproduct_p^.packing_list_index <= UPPERBOUND (previous_corr_packing_list_rec.
                subproduct_processing_records_p^)) AND (current_subproduct_p^.directory_record_p^.
                active_information.sif_identifier = previous_corr_packing_list_rec.
                subproduct_processing_records_p^ [current_subproduct_p^.packing_list_index].
                subproduct_info_pointers.attributes_p^.sif_identifier) THEN
            previous_corr_subp_info_ptrs := previous_corr_packing_list_rec.
                  subproduct_processing_records_p^ [current_subproduct_p^.packing_list_index].
                  subproduct_info_pointers;
          ELSE {Original packing list replaced, can't this subproduct's previous corrections.}
            osp$set_status_abnormal ('RA', rae$previous_corr_packlist_bad,
                  validation_list_header_p^.packing_list_name, local_status);
            osp$generate_log_message ($pmt$ascii_logset [pmc$job_log], local_status, ignore_status);
            local_status.normal := TRUE;
            previous_corr_subp_info_ptrs.attributes_p := NIL;     {No previous correction info available.}
          IFEND;
        ELSE
          previous_corr_subp_info_ptrs.attributes_p := NIL;       {No previous corrections info available.}
        IFEND;

        establish_subproduct_paths (current_subproduct_p^.directory_record_p, previous_corr_subp_info_ptrs,
              installation_control_record.processing_header_p^.installation_defaults.correction_bases,
              installation_control_record.subproduct_processing_records_p^
              [current_subproduct_p^.processing_records_index], subproduct_paths,
              installation_control_record.processing_seq_p, status);
        IF NOT status.normal THEN
          EXIT /main/;
        IFEND;

        init_validation_info_record (previous_corr_subp_info_ptrs, subproduct_paths [rac$active_level_path],
              installation_control_record.subproduct_processing_records_p^
              [current_subproduct_p^.processing_records_index],
              validation_list_header_p^.subproduct_state, validation_info_record);

        validate_subproduct (subproduct_paths, validation_info_record,
              installation_control_record.subproduct_processing_records_p^
              [current_subproduct_p^.processing_records_index].subproduct_info_pointers.element_list_p,
              installation_control_record.subproduct_processing_records_p^
              [current_subproduct_p^.processing_records_index].task_set,
              subproduct_validation_errors, status);
        IF NOT status.normal THEN
          EXIT /main/;
        IFEND;

        IF (installation_control_record.subproduct_processing_records_p^
              [current_subproduct_p^.processing_records_index].task_set = $rat$task_selections []) THEN
          stringrep(operator_message, operator_message_length, 'The correction to subproduct ',
                validation_info_record.subproduct_name(1, clp$trimmed_string_size(validation_info_record.
                subproduct_name)),
                ' will not be installed due to missing file(s).  See file ',
                installation_control_record.processing_header_p^.installation_defaults.
                installation_logs.path(1,installation_control_record.processing_header_p^.
                installation_defaults.installation_logs.size),
                '.{installation_identifier}.command_log for details');
          ofp$send_operator_message(operator_message (1, operator_message_length), ofc$system_operator,
                {acknowledgement_allowed =} TRUE, ignore_status);
          ofp$receive_operator_response (ofc$system_operator, osc$wait,
                response_from_operator, ignore_status);
        IFEND;
        current_subproduct_p := current_subproduct_p^.next_subproduct_p;
        validation_errors := (validation_errors OR subproduct_validation_errors);
      WHILEND;

    END /main/;

    IF packing_list_open THEN
      fsp$close_file (packing_list_fid, local_status);
      IF status.normal AND (NOT local_status.normal) THEN
        status := local_status;
      IFEND;
    IFEND;

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

    osp$disestablish_cond_handler;

  PROCEND process_subp_validation_list;
?? OLDTITLE, NEWTITLE := 'validate_file', EJECT ??

{ PURPOSE:
{   This interface processes an element to prepare its correction_directives.
{   This processing includes determination if a previous correction can be
{   used and if it can't be used, where the correction base (if its needed)
{   for applying the correction is located.
{
{ DESIGN:
{   We first determine if the base level file for this element is present.
{   If the file is not present then we will not correct the subproduct since
{   it has been corrupted or atleast partially deleted from the system.
{
{   If element is inactive, then this is a subproduct is using a version based
{   installation scheme for the corrections.  All that is needed is to
{   make the element active and set the correction directives for the element
{   so that the release file will be copied forward into the version catalog
{   for this level of the subproduct.
{
{   If the element is active, determine if the base level file has been
{   previously corrected.  This is done by trying to locate the element
{   in the SIF (packing list) for the active level of the subproduct if
{   active level information is available).  If we do locate an element,
{   it can only be used as a previous correction if it was active --
{   inactive elements represent a file in a version based correction
{   which was not corrected.  If we locate an active element, and we want
{   to use it corrected and we want to use it, then the element list will
{   be updated appropriately for the type of installation scheme being
{   used.
{
{   If there was no previous correction, or we can't use it, then the file
{   must be corrected.  If this is an object library, we must locate the
{   correction base for the file and record this information in the correction
{   directives.  If this is not an object library, a correction base is not
{   needed, and the correction directives are updated to indicate that
{   processing is limited to replacing the file only.
{
{ NOTES:


  PROCEDURE validate_file
    (    element_paths: rat$element_paths;
         validation_info_record: rat#validation_info_record;
         element_p {input, output} : ^rat$element;
     VAR task_set: rat$task_selections;
     VAR validation_error: boolean;
     VAR status: ost$status);

    VAR
      base_file_exists: boolean,
      element_located: boolean,
      file_previously_corrected: boolean,
      ignore_status: ost$status,
      local_subproduct_info_seq_ptr: ^rat$subproduct_info_sequence,
      previous_correction_element_p: ^rat$element,
      previous_correction_usable: boolean;


    status.normal := TRUE;

    validation_error := FALSE;
    base_file_exists := FALSE;

    { Ensure the file exists where the original release subproduct was installed

    verify_file_exists (element_paths [rac$base_level_path], base_file_exists, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    IF NOT base_file_exists THEN
      log_missing_file_message (rae$base_file_missing, element_paths [rac$base_level_path], NIL
            {No second file path} , validation_info_record.subproduct_name, ignore_status);
      task_set := $rat$task_selections [];
      RETURN;
    IFEND;

    IF element_p^.active_element THEN      {The element has a correction.}

      { Attempt to locate a previous correction to the file in the packing list for the
      { active level.  This is done even if the previous correction cannot
      { be used because the existance of a previous correction also determines
      { where the correction base is located.

      file_previously_corrected := FALSE;
      IF validation_info_record.active_subproduct_info_seq_p <> NIL THEN
        previous_correction_element_p := validation_info_record.active_element_list_p;
        local_subproduct_info_seq_ptr := validation_info_record.active_subproduct_info_seq_p;
        rap$locate_element (element_paths [rac$active_level_path], validation_info_record.active_path_index,
              local_subproduct_info_seq_ptr, previous_correction_element_p, element_located);
        IF (element_located) and (previous_correction_element_p^.active_element) THEN
          file_previously_corrected := TRUE;
        ELSE
          previous_correction_element_p := NIL;
        IFEND;
      IFEND;

     { Process the previous correction if we have one and are allowed to use it.

      previous_correction_usable := FALSE;
      IF (validation_info_record.allowed_to_use_previous_corrs) AND (file_previously_corrected) THEN
        check_previous_correction (element_paths, validation_info_record, previous_correction_element_p,
              element_p, previous_correction_usable, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
      IFEND;

      { Process elements for which we don't have or want to use a previous correction.

      IF NOT (file_previously_corrected AND previous_correction_usable) THEN
        IF element_p^.correction_format = rac$object_library THEN
          locate_correction_base (element_paths, validation_info_record, file_previously_corrected, element_p,
                validation_error, status);
          IF (NOT status.normal) OR validation_error THEN
            RETURN;
          IFEND;
        ELSE
          element_p^.correction_directives := $rat$correction_directives [rac$use_replacement_file];
        IFEND;
      IFEND;
    ELSE {The element has no correction and is in a version based correction.}
      element_p^.active_element := TRUE;
      element_p^.correction_directives := $rat$correction_directives [rac$use_release_file];
    IFEND;

  PROCEND validate_file;

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

{ PURPOSE:
{   This interface processes the elements of a subproduct to set the proper
{   processing attributes for each element of the subproduct.
{
{ DESIGN:
{   Loop through the element list using the standard element list traversal
{   algorithm.
{
{   This procedure processes all the elements at one catalog level, calling
{   itself recursively if the catalog contains a subcatalog.
{
{   In order to ensure that all catalog's are created for version based
{   corrections, all catalog element's are set active.
{
{ NOTES:
{   This code assumes that if an element is inactive, that the
{   installation scheme is version based.
{
{   In a cycle based correction, it is possible that all files in a
{   catalog have been previously corrected.  In this case, the catalog
{   element should be made inactive.  Since it only wastes a small amount
{   of time to "stage/activate" a catalog, no attempt is made in this
{   code to set catalog elements inactive.

  PROCEDURE validate_subproduct
    (    element_paths: rat$element_paths;
         validation_info_record: rat#validation_info_record;
         element_p {output} : ^rat$element;
     VAR task_set: rat$task_selections;
     VAR validation_errors: boolean;
     VAR status: ost$status);

    VAR
      previous_correction_element_p: ^rat$element,
      current_element_p: ^rat$element,
      current_element_paths: rat$element_paths,
      element_validation_error: boolean,
      first_element_down_p: ^rat$element,
      i: integer,
      path_index: rat$installation_paths;

    status.normal := TRUE;
    previous_correction_element_p := NIL;

    { Create a new array of PF paths which contains path's one larger than
    { each of the path arrays in ELEMENT_PATHS and initialize each path.
    { This array will be used to construct the PF
    { paths for the files and subcatalogs that reside in the current catalog.

    FOR path_index := LOWERBOUND (element_paths) TO UPPERBOUND (element_paths) DO
      IF element_paths [path_index] <> NIL THEN
        PUSH current_element_paths [path_index]: [1 .. UPPERBOUND (element_paths [path_index]^) + 1];
        FOR i := 1 TO UPPERBOUND (element_paths [path_index]^) DO
          current_element_paths [path_index]^ [i] := element_paths [path_index]^ [i];
        FOREND;
      ELSE
        current_element_paths [path_index] := NIL;
      IFEND;
    FOREND;

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

    current_element_p := element_p;
    validation_errors := FALSE;

    WHILE current_element_p <> NIL DO

      { Add current file name to end of each path.

      FOR path_index := LOWERBOUND (current_element_paths) TO UPPERBOUND (current_element_paths) DO
        IF current_element_paths [path_index] <> NIL THEN
          current_element_paths [path_index]^ [UPPERBOUND (current_element_paths [path_index]^)] :=
                current_element_p^.name;
        IFEND;
      FOREND;

      IF current_element_p^.element_type = rac$file THEN

        validate_file (current_element_paths, validation_info_record, current_element_p,
              task_set, element_validation_error, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

      ELSE {current_element_p^.element_type = rac$catalog}

        IF current_element_p^.element_count <> 0 THEN
          first_element_down_p := #PTR (current_element_p^.first_element_down_p,
                validation_info_record.subproduct_info_seq_p^);
          validate_subproduct (current_element_paths, validation_info_record, first_element_down_p,
                task_set, element_validation_error, status);
          IF NOT status.normal THEN
            RETURN;
          IFEND;
        IFEND;

        { Turn on inactive catalogs.

        IF (NOT current_element_p^.active_element) THEN
          current_element_p^.active_element := TRUE;
        IFEND;

      IFEND;

      validation_errors := (validation_errors OR element_validation_error);
      current_element_p := #PTR (current_element_p^.next_element_across_p,
            validation_info_record.subproduct_info_seq_p^);
    WHILEND;

  PROCEND validate_subproduct;

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

{ PURPOSE:
{   This procedure verifies that a file exists, returning a boolean
{   flag with the answer.
{
{ DESIGN:
{   Convert PFT$PATH pointer to a string and use get_file_attributes to
{   determine if the file exists.
{ NOTES:

  PROCEDURE verify_file_exists
    (    pft_file_p: ^pft$path;
     VAR file_exists: boolean;
     VAR status: ost$status);

    VAR
      existing_file: boolean,
      file: rat$path,
      ignore_attributes: array [1 .. 1] of amt$get_item,
      ignore_contains_data: boolean,
      local_file: boolean;

    status.normal := TRUE;
    file_exists := FALSE;
    ignore_attributes [1].key := amc$file_length;

    rap$convert_path_to_str (pft_file_p^, file);

    amp$get_file_attributes (file.path (1, file.size), ignore_attributes, local_file, existing_file,
          ignore_contains_data, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF (local_file) OR (existing_file) THEN
      file_exists := TRUE;
    IFEND;

  PROCEND verify_file_exists;
?? OLDTITLE ??

MODEND ram$validate_for_correction;



