?? RIGHT := 110 ??
?? NEWTITLE := 'INSTALL_SOFTWARE Utility: RAP$ESTABLISH_PROCESSING_CNTRLS Interface.' ??
MODULE ram$establish_processing_cntrls;

{ PURPOSE:
{   This module contains the interface and procedures that establish
{   processing controls.
{
{ DESIGN:
{   The compiled module resides in RAF$LIBRARY.
{
{ NOTES:
{

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc rac$command_log_name
*copyc rac$inss_processor_version
*copyc rac$summary_file_level
*copyc rac$summary_file_name
*copyc rae$install_software_cc
*copyc rat$installation_control_record
*copyc rat$processing_summary_types
?? POP ??
*copyc amp$get_segment_pointer
*copyc amp$set_segment_eoi
*copyc clp$trimmed_string_size
*copyc fsp$close_file
*copyc fsp$open_file
*copyc osp$append_status_parameter
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc osp$set_status_abnormal
*copyc pmp$get_compact_date_time
*copyc rap$assign_install_identifier
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

  TYPE
    job_record = record
      identifier: rat$job_identifier,
      log_file_name: ost$name,
      subproduct_count: rat$subproduct_count,
    recend,

    rat#job_list = record
      length: rat$job_count,
      records_p: ^array [ * ] of job_record,
    recend;

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

{ PURPOSE:
{   This interface establishes the controls required for processing an
{   installation event.
{
{ DESIGN:
{   An installation identifier is assigned to the installation event and the
{   installation identifier catalog is created.  The number of jobs required
{   for processing are calculated and job identifiers and log file names are
{   assigned.  The processing summary file and the job processing records
{   are established base on the number of jobs required.
{
{   The distinction between a job status record (found in the processing
{   summary file) and a job processing record is that the job status record
{   is used to register current processing status for the job and the job
{   processing record is used in setting up the job to be executed.
{
{   The job list is a temporary variable to collect information needed in
{   creating the processing summary file and the job processing records.
{
{ NOTES:
{

  PROCEDURE [XDCL] rap$establish_processing_cntrls
    (    multiple_job_processing: boolean;
         execute_in_job_of_caller: boolean;
     VAR installation_control_record {input, output} : rat$installation_control_record;
     VAR status: ost$status);

    VAR
      job_list: rat#job_list;


    status.normal := TRUE;

    rap$assign_install_identifier (installation_control_record.processing_header_p^.installation_command,
          installation_control_record.processing_header_p^.installation_defaults.installation_logs,
          installation_control_record.processing_header_p^.packing_list_name,
          installation_control_record.processing_header_p^.installation_identifier, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    job_list.length := 0;
    PUSH job_list.records_p: [1 .. UPPERBOUND (installation_control_record.medium_processing_records_p^)];

    assign_job_identifiers (multiple_job_processing, execute_in_job_of_caller, installation_control_record,
          job_list, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    create_processing_summary_file (job_list, installation_control_record, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    establish_job_processing_recds (job_list, installation_control_record, status);

  PROCEND rap$establish_processing_cntrls;

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

{ PURPOSE:
{   This procedure determines the number of jobs required to perform the
{   installation event and creates job identifiers for each job.
{
{ DESIGN:
{   The job identifier was orignally set as a null name in all of the medium
{   and subproduct processing records.
{
{   Only tape orders can be processed using multiple jobs, a job per tape.
{   When multiple jobs are being defined, the log file is named by taking
{   the string 'JOB_LOG_VSN_' and appending the vsn for the tape associated
{   with the job.
{
{   When a single job is being defined and processing is to take place in
{   job of caller, the log file will be the command log.  Otherwise, when
{   not in job of caller the string 'JOB_LOG' is used.
{
{ NOTES:
{   The current job's identifier is updated to the assigned job identifier
{   when single job processing is true.  Under current design it will be
{   the job to carry on the rest of the processing.
{

  PROCEDURE assign_job_identifiers
    (    multiple_job_processing: boolean;
         execute_in_job_of_caller: boolean;
     VAR installation_control_record {input, output} : rat$installation_control_record;
     VAR job_list {input, output} : rat#job_list;
     VAR status: ost$status);


    VAR
      installation_identifier: rat$installation_identifier,
      job_identifier: rat$job_identifier,
      length: integer,
      log_file_name: ost$name,
      medium_index: rat$tape_count,
      subproduct_index: rat$subproduct_count,
      vsn: rmt$external_vsn;


    status.normal := TRUE;
    installation_identifier := installation_control_record.processing_header_p^.installation_identifier;

    IF NOT multiple_job_processing OR (installation_control_record.packing_list_pointers.order_medium =
          rac$disk) THEN

      { There will only be one job.  For tape orders the one job will load from all the tapes with
      { subproducts to install.

      job_identifier := installation_identifier;

      job_list.length := 1;
      job_list.records_p^ [job_list.length].identifier := job_identifier;
      IF execute_in_job_of_caller THEN
        job_list.records_p^ [job_list.length].log_file_name := rac$command_log_name;
      ELSE {batch processing}
        job_list.records_p^ [job_list.length].log_file_name := 'JOB_LOG';
      IFEND;

      job_list.records_p^ [job_list.length].subproduct_count := 0;

      FOR medium_index := 1 TO UPPERBOUND (installation_control_record.medium_processing_records_p^) DO
        IF installation_control_record.medium_processing_records_p^ [medium_index].subproduct_count > 0 THEN
          installation_control_record.medium_processing_records_p^ [medium_index].job_identifier :=
                job_identifier;

          job_list.records_p^ [job_list.length].subproduct_count :=
                job_list.records_p^ [job_list.length].subproduct_count +
                installation_control_record.medium_processing_records_p^ [medium_index].subproduct_count;

        IFEND;
      FOREND;

      installation_control_record.job_identifier := job_identifier;

    ELSE { medium is tape and multiple job processing allowed}

      { There will be one job for each tape with subproducts to install.

      FOR medium_index := 1 TO UPPERBOUND (installation_control_record.medium_processing_records_p^) DO
        IF installation_control_record.medium_processing_records_p^ [medium_index].subproduct_count > 0 THEN
          STRINGREP (job_identifier, length, installation_identifier
                (1, clp$trimmed_string_size (installation_identifier)), '_',
                installation_control_record.packing_list_pointers.tape_vsns_p^ [medium_index].external_vsn);
          installation_control_record.medium_processing_records_p^ [medium_index].job_identifier :=
                job_identifier (1, length);

          vsn := installation_control_record.packing_list_pointers.tape_vsns_p^ [medium_index].external_vsn;
          STRINGREP (log_file_name, length, 'JOB_LOG_VSN_', vsn (1, clp$trimmed_string_size (vsn)));

          job_list.length := job_list.length + 1; {length initialized to 0 when created}
          job_list.records_p^ [job_list.length].identifier := installation_control_record.
                medium_processing_records_p^ [medium_index].job_identifier;
          job_list.records_p^ [job_list.length].log_file_name := log_file_name (1, length);
          job_list.records_p^ [job_list.length].subproduct_count :=
                installation_control_record.medium_processing_records_p^ [medium_index].subproduct_count;

        IFEND;
      FOREND;

    IFEND;

    { Set the job identifier field in the subproduct processing records to the identifier
    { for the job responsible for each subproduct to be installed.

    FOR subproduct_index := 1 TO UPPERBOUND (installation_control_record.subproduct_processing_records_p^) DO
      IF installation_control_record.subproduct_processing_records_p^ [subproduct_index].task_set <>
            $rat$task_selections [] THEN
        IF installation_control_record.packing_list_pointers.order_medium = rac$tape THEN
          medium_index := installation_control_record.packing_list_pointers.
                tape_subproduct_indexer_p^ [subproduct_index].primary_tape_vsn;
        ELSE {order medium = rac$disk}
          medium_index := 1;
        IFEND;

        installation_control_record.subproduct_processing_records_p^ [subproduct_index].job_identifier :=
              installation_control_record.medium_processing_records_p^ [medium_index].job_identifier;

      IFEND;
    FOREND;

  PROCEND assign_job_identifiers;

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

{ PURPOSE:
{   This procedure creates the processing summary file for the current
{   installation event.
{
{ DESIGN:
{   The processing summary file is created under the installation
{   identifier catalog.  It is opened as a segment access file.  After
{   opening the processing summary file a sequence descriptor, a header and
{   an array of job status records are created and initialized in the
{   sequence.
{
{   There is one job status record for each job required to process the
{   installation event.  The job list that was passed in defines the number
{   of jobs required and contains additional job data that is copied into
{   the job status records
{
{ NOTES:
{

  PROCEDURE create_processing_summary_file
    (    job_list: rat#job_list;
         installation_control_record: rat$installation_control_record;
     VAR status: ost$status);


    VAR
      attachment_options: array [1 .. 3] of fst$attachment_option,
      creation_date_time: ost$date_time,
      file_opened: boolean,
      i: rat$job_count,
      ignore_status: ost$status,
      job_status_records_p: ^rat$job_status_records,
      length: integer,
      local_status: ost$status,
      sequence_descriptor_p: ^rat$sequence_descriptor,
      summary_file_fid: amt$file_identifier,
      summary_file_header_p: ^rat$processing_summary_header,
      summary_file_path: fst$path,
      summary_file_segment_p: amt$segment_pointer;


?? 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 processing
{   summary file 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;

      fsp$close_file (summary_file_fid, ignore_status);

    PROCEND abort_handler;

?? OLDTITLE, EJECT ??


    status.normal := TRUE;

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

{ Assemble the path to the processing summary file using the installation logs path,
{ the installation identifier and the processing summary file name.

    STRINGREP (summary_file_path, length, installation_control_record.processing_header_p^.
          installation_defaults.installation_logs.path (1, installation_control_record.processing_header_p^.
          installation_defaults.installation_logs.size), '.',
          installation_control_record.processing_header_p^.installation_identifier
          (1, clp$trimmed_string_size (installation_control_record.processing_header_p^.
          installation_identifier)), '.', rac$summary_file_name);


    osp$establish_block_exit_hndlr (^abort_handler);

  /main/
    BEGIN

      file_opened := TRUE;
      fsp$open_file (summary_file_path (1, length), amc$segment, ^attachment_options, NIL, NIL, NIL, NIL,
            summary_file_fid, status);
      IF NOT status.normal THEN
        file_opened := FALSE;
        EXIT /main/;
      IFEND;

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

      RESET summary_file_segment_p.sequence_pointer;
      NEXT sequence_descriptor_p IN summary_file_segment_p.sequence_pointer;
      IF sequence_descriptor_p = NIL THEN
        osp$set_status_abnormal ('RA', rae$accessed_beyond_segment_eoi, 'PROCESSING SUMMARY FILE', status);
        osp$append_status_parameter (osc$status_parameter_delimiter, 'SEQUENCE DESCRIPTOR', status);
        EXIT /main/;
      IFEND;

      pmp$get_compact_date_time (creation_date_time, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      sequence_descriptor_p^.processor_version := rac$inss_processor_version;
      sequence_descriptor_p^.sequence_creation_date_time := creation_date_time;
      sequence_descriptor_p^.sequence_type := rac$processing_summary_sequence;
      sequence_descriptor_p^.sequence_level := rac$summary_file_level;

      NEXT summary_file_header_p IN summary_file_segment_p.sequence_pointer;
      IF summary_file_header_p = NIL THEN
        osp$set_status_abnormal ('RA', rae$accessed_beyond_segment_eoi, 'PROCESSING SUMMARY FILE', status);
        osp$append_status_parameter (osc$status_parameter_delimiter, 'HEADER', status);
        EXIT /main/;
      IFEND;

      NEXT job_status_records_p: [1 .. job_list.length] IN summary_file_segment_p.sequence_pointer;
      IF job_status_records_p = NIL THEN
        osp$set_status_abnormal ('RA', rae$accessed_beyond_segment_eoi, 'PROCESSING SUMMARY FILE', status);
        osp$append_status_parameter (osc$status_parameter_delimiter, 'JOB STATUS RECORDS', status);
        EXIT /main/;
      IFEND;

      summary_file_header_p^.job_count := job_list.length;
      summary_file_header_p^.job_status_records_rel_p := #REL (job_status_records_p,
            summary_file_segment_p.sequence_pointer^);

      FOR i := 1 TO job_list.length DO
        job_status_records_p^ [i].job_identifier := job_list.records_p^ [i].identifier;
        job_status_records_p^ [i].log_file_name := job_list.records_p^ [i].log_file_name;
        job_status_records_p^ [i].date_time := creation_date_time;
        job_status_records_p^ [i].number_of_steps := installation_control_record.processing_header_p^.
              number_of_steps;
        job_status_records_p^ [i].step_number := 0;
        job_status_records_p^ [i].step := rac$null_step;
        job_status_records_p^ [i].step_status := rac$step_started;
        job_status_records_p^ [i].initial_subproduct_count := job_list.records_p^ [i].subproduct_count;
        job_status_records_p^ [i].started_subproduct_count := 0;
        job_status_records_p^ [i].completed_subproduct_count := 0;
      FOREND;

      amp$set_segment_eoi (summary_file_fid, summary_file_segment_p, status);

    END /main/;

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

    osp$disestablish_cond_handler;

  PROCEND create_processing_summary_file;

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

{ PURPOSE:
{   This procedure establishes the job processing records in the processing
{   sequence.
{
{ DESIGN:
{   There is one job processing record for each job required to process the
{   installation event.  The job list that was passed in defines the number
{   of jobs required and contains additional job data that is copied into
{   the job processing records.
{
{ NOTES:
{

  PROCEDURE establish_job_processing_recds
    (    job_list: rat#job_list;
     VAR installation_control_record: rat$installation_control_record;
     VAR status: ost$status);


    VAR
      i: rat$job_count;


    status.normal := TRUE;

    NEXT installation_control_record.job_processing_records_p: [1 .. job_list.length] IN
          installation_control_record.processing_seq_p;
    IF installation_control_record.job_processing_records_p = NIL THEN
      osp$set_status_abnormal ('RA', rae$accessed_beyond_segment_eoi, 'PROCESSING SEQUENCE', status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'JOB PROCESSING RECORDS', status);
      RETURN;
    IFEND;

    installation_control_record.processing_header_p^.job_processing_rec_rel_p :=
          #REL (installation_control_record.job_processing_records_p,
          installation_control_record.processing_seq_p^);

    FOR i := 1 TO job_list.length DO
      installation_control_record.job_processing_records_p^ [i].job_identifier :=
            job_list.records_p^ [i].identifier;
      installation_control_record.job_processing_records_p^ [i].log_file_name :=
            job_list.records_p^ [i].log_file_name;
    FOREND;

  PROCEND establish_job_processing_recds;
MODEND ram$establish_processing_cntrls;
