?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Network File Transfer : Submit Multi-Record Job' ??
MODULE nfm$submit_multi_record_job;

{ PURPOSE:
{   This module contains the procedure to create a RHF structured (multiple
{   records) job file.
{
{ DESIGN:
{   Create a job by taking each file (in the order specified) and making it
{   a Trailing_Character_Delimited file and then copy this temporary file as
{   a Variable record on the RHF structured job file.  Then submit this
{   RHF structured job file to the remote system as specified on the calling
{   command.
{
{ NOTES:
{   The job file created must NOT have an EMPTY file as the first record,
{   as this would be an empty command record.
{
{   When this RHF structured job is submitted to the system, it is required
{   that the job submission options have:
{     1. DATA_MODE set to RHF_STRUCTURED and
{     2. LOGIN_FAMILY_SUPPLIED set to FALSE, so that NOS/VE does not try to
{        crack the first record as a LOGIN command.
{
{   The last restriction for submitting of the RHF structured job is that the
{   job must be transferred by a Queue Transfer application to a remote system.
{   This is required so that when the job is received on the remote system the
{   variable record header is stripped off of each of the job records.  That is
{   why the JOB_DESTINATION_USAGE parameter has the keyword values of 'VE',
{   'LOCAL' and 'VE_QTF' as hidden keys.

?? NEWTITLE := 'Global References', EJECT ??
*copyc amp$get_file_attributes
*copyc amp$get_next
*copyc amp$put_next
*copyc amp$return
*copyc clp$change_variable
*copyc clp$evaluate_parameters
*copyc fsp$close_file
*copyc fsp$copy_file
*copyc fsp$open_file
*copyc jmp$submit_job
*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$set_status_abnormal
*copyc pmp$get_unique_name
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] nfp$_submit_multi_record_job', EJECT ??

{    The purpose of this command is to create a job that has multiple
{ records that can be submitted to a non-NOS/VE system.  However,
{ this does not prevent a user from creating a job for a NOS/VE
{ system, but this NOS/VE job must be transferred to a remote
{ system using a Queue Transfer application.
{
{ NOTES:
{   The block_exit_condition_handler is used to return all scratch
{   files and scratch segments that were created by this command procedure.

  PROCEDURE [XDCL] nfp$_submit_multi_record_job
    (    parameter_list: clt$parameter_list;
     VAR status: ost$status);

*copy nft$pdt_submit_multi_record_job

    CONST
      local_catalog_name = ':$LOCAL.',
      local_catalog_name_length = 8,
      max_submission_options = 7,
      record_delimiting_character = $CHAR(1f(16));

    VAR
      block_exit_condition_handler: pmt$condition_handler,
      existing_file: boolean,
      file_byte_address: amt$file_byte_address,
      file_contains_data: boolean,
      file_is_local: boolean,
      file_list_entry: ^clt$data_value,
      file_list_entry_number: integer,
      file_position: amt$file_position,
      file_transfer_count: amt$transfer_count,
      ignore_status: ost$status,
      job_file_creation_attributes: array [1 .. 1] of fst$file_cycle_attribute,
      job_file_identifier: amt$file_identifier,
      job_file_name: string (osc$max_name_size + local_catalog_name_length),
      job_submission_options: ^jmt$job_submission_options,
      ptr_scratch_segment: amt$segment_pointer,
      system_job_name: ^clt$data_value,
      system_supplied_name: jmt$system_supplied_name,
      t_record_file_attribute: ^fst$file_cycle_attributes,
      temporary_file_attach_options: array [1 .. 3] of fst$attachment_option,
      temporary_file_get_attributes: array [1 .. 1] of amt$get_item,
      temporary_file_identifier: amt$file_identifier,
      temporary_file_name: string (osc$max_name_size + local_catalog_name_length),
      temporary_file_override_attr: array [1 .. 2] of fst$file_cycle_attribute,
      unique_name: ost$name,
      working_storage_area: ^array [1 .. *] of char;

?? NEWTITLE := 'exit_condition_handler', EJECT ??

    PROCEDURE exit_condition_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;

{  close and return all files created by this command

      fsp$close_file (job_file_identifier, ignore_status);
      amp$return (job_file_name, ignore_status);

      fsp$close_file (temporary_file_identifier, ignore_status);
      amp$return (temporary_file_name, ignore_status);

{  delete the scratch segment that was used as the working storage
{  area for the creation of the rhf structured file.

      mmp$delete_scratch_segment (ptr_scratch_segment, ignore_status);

   PROCEND exit_condition_handler;
?? OLDTITLE, EJECT ??
    status.normal := TRUE;

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

{  the keyword values NTF or QTF are the only valid keyword options for the JOB_DESTINATION_USAGE parameter
{  in particular the keyword values VE, VE_LOCAL and VE_QTF are invalid because the job must be
{  transferred through a queue transfer application to convert the RHF_STRUCTURE job file to a standard file

    IF pvt [p$job_destination_usage].value^.kind = clc$keyword THEN
      IF NOT ((pvt [p$job_destination_usage].value^.keyword_value = jmc$ntf_usage) OR
            (pvt [p$job_destination_usage].value^.keyword_value = jmc$qtf_usage)) THEN
        osp$set_status_abnormal ('JM', jme$invalid_parameter, pvt [p$job_destination_usage].value^
              .keyword_value, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, 'JOB_DESTINATION_USAGE', status);
        osp$append_status_parameter (osc$status_parameter_delimiter, 'SUBMIT_MULTI_RECORD_JOB', status);
        RETURN; {----->
      IFEND;
    IFEND;

    file_position := amc$boi;

{  define the record type for the rhf structured file that is to be submitted to the system.

    job_file_creation_attributes [1].selector := fsc$record_type;
    job_file_creation_attributes [1].record_type := amc$variable;

{  define the attach options for the temporary file that is a copy of the user's file.
{  these attach options are needed because the record type is being overridden when it is opened.

    temporary_file_attach_options [1].selector := fsc$access_and_share_modes;
    temporary_file_attach_options [1].access_modes.selector := fsc$specific_access_modes;
    temporary_file_attach_options [1].access_modes.value := $fst$file_access_options [fsc$read];
    temporary_file_attach_options [1].share_modes.selector := fsc$specific_share_modes;
    temporary_file_attach_options [1].share_modes.value := $fst$file_access_options [fsc$read];
    temporary_file_attach_options [2].selector := fsc$open_share_modes;
    temporary_file_attach_options [2].open_share_modes := $fst$file_access_options [fsc$read];
    temporary_file_attach_options [3].selector := fsc$open_position;
    temporary_file_attach_options [3].open_position := amc$open_at_boi;

{  define the file attributes that are needed to get from the temporary file.

    temporary_file_get_attributes [1].key := amc$file_length;

{  define the override attributes for the temporary file.

    temporary_file_override_attr [1].selector := fsc$block_type;
    temporary_file_override_attr [1].block_type := amc$system_specified;
    temporary_file_override_attr [2].selector := fsc$record_type;
    temporary_file_override_attr [2].record_type := amc$undefined;

{  define the record type for the temporary file that is a copy of the user's file.

    PUSH t_record_file_attribute: [1 .. 2];
    t_record_file_attribute^ [1].selector := fsc$record_type;
    t_record_file_attribute^ [1].record_type := amc$trailing_char_delimited;
    t_record_file_attribute^ [2].selector := fsc$record_delimiting_character;
    t_record_file_attribute^ [2].record_delimiting_character := record_delimiting_character;

{  create unique file names for the temporary file and the file that is to be submitted to the system.

    pmp$get_unique_name (unique_name, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    job_file_name := local_catalog_name;
    job_file_name ((local_catalog_name_length + 1), *) := unique_name;

    pmp$get_unique_name (unique_name, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    temporary_file_name := local_catalog_name;
    temporary_file_name ((local_catalog_name_length + 1), *) := unique_name;

    block_exit_condition_handler := ^exit_condition_handler;
    osp$establish_block_exit_hndlr (block_exit_condition_handler);

{  create a scratch segment that will be used as the working storage area
{  for the creation of the file that is to be submitted to the system.

    mmp$create_scratch_segment (amc$sequence_pointer, mmc$as_sequential, ptr_scratch_segment, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

{  open the file that is to be submitted to the system.

    fsp$open_file (job_file_name, amc$record, NIL, NIL, ^job_file_creation_attributes, NIL, NIL,
          job_file_identifier, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

{  get the first user's file.

    file_list_entry_number := 1;
    file_list_entry := pvt [p$file].value;

  /use_scratch_segment/
    WHILE file_list_entry <> NIL DO

{  copy the user's file to a T record temporary file.

      fsp$copy_file (file_list_entry^.element_value^.file_value^, temporary_file_name, NIL, NIL,
            t_record_file_attribute, status);
      IF status.normal THEN

{  get the size of the temporary file.

        amp$get_file_attributes (temporary_file_name, temporary_file_get_attributes, file_is_local,
              existing_file, file_contains_data, status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;

{  the check for file length of 1 is to determine if the file is empty because each T-record
{  file has at least one character in each record, the record_delimiting_character.

        IF temporary_file_get_attributes [1].file_length > 1 THEN

{  the temporary file is not empty so copy this file to the job file.

          RESET ptr_scratch_segment.sequence_pointer;
          NEXT working_storage_area: [1 .. temporary_file_get_attributes [1].file_length] IN
                ptr_scratch_segment.sequence_pointer;

{  open and write the temporary T record file as an UNDEFINED record.

          fsp$open_file (temporary_file_name, amc$record, ^temporary_file_attach_options, NIL, NIL, NIL,
                ^temporary_file_override_attr, temporary_file_identifier, status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;

          amp$get_next (temporary_file_identifier, working_storage_area, #SIZE (working_storage_area^),
                file_transfer_count, file_byte_address, file_position, status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;

          amp$put_next (job_file_identifier, working_storage_area, file_transfer_count, file_byte_address,
                status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;

{  close the temporary version of the user's file.

          fsp$close_file (temporary_file_identifier, status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;
        ELSEIF file_list_entry_number > 1 THEN

{  the temporary file is empty but it is not the first file to copy into the job file.
{  therefore, this will allow for an empty record within the job file.

          amp$put_next (job_file_identifier, working_storage_area, 0, file_byte_address, status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;
        ELSE

{  the first temporary file is empty, therefore this would create an invalid job
{  (first record of the job would be empty).

          osp$set_status_abnormal ('FS', fse$empty_input_file, file_list_entry^.element_value^.file_value^,
                status);
          RETURN; {----->
        IFEND;

{  return the temporary version of the user's file.

        amp$return (temporary_file_name, ignore_status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
      ELSEIF NOT status.normal AND (status.condition = fse$empty_input_file) AND (file_list_entry_number > 1)
            THEN
        amp$put_next (job_file_identifier, working_storage_area, 0, file_byte_address, status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
      ELSE
        RETURN; {----->
      IFEND;

{  get the next file in the list of user's files.

      file_list_entry := file_list_entry^.link;
      file_list_entry_number := file_list_entry_number + 1;
    WHILEND /use_scratch_segment/;

{ close the scratch segment that was used as the working storage area.

    mmp$delete_scratch_segment (ptr_scratch_segment, ignore_status);

{  close the file that is to be submitted to the system.

    fsp$close_file (job_file_identifier, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{  create the job submission options required to submit this file.

    PUSH job_submission_options: [1 .. max_submission_options];

    job_submission_options^ [1].key := jmc$data_mode;
    job_submission_options^ [1].data_mode := jmc$rhf_structure;

    job_submission_options^ [2].key := jmc$login_command_supplied;
    job_submission_options^ [2].login_command_supplied := FALSE;

{  get the rest of the job submission options from the parameters for this command.

    job_submission_options^ [3].key := jmc$job_destination_family;
    IF pvt [p$job_destination].value^.kind = clc$name THEN
      job_submission_options^ [3].job_destination_family := pvt [p$job_destination].value^.name_value;
    ELSE
      job_submission_options^ [3].job_destination_family := pvt [p$job_destination].value^.string_value^;
    IFEND;

    job_submission_options^ [4].key := jmc$job_destination_usage;
    IF pvt [p$job_destination_usage].value^.kind = clc$name THEN
      job_submission_options^ [4].job_destination_usage := pvt [p$job_destination_usage].value^.name_value;
    ELSE
      job_submission_options^ [4].job_destination_usage := pvt [p$job_destination_usage].value^.keyword_value;
    IFEND;

    job_submission_options^ [5].key := jmc$output_disposition;
    IF pvt [p$output_disposition].value^.keyword_value = 'DISCARD_ALL_OUTPUT' THEN
      job_submission_options^ [5].output_disposition.key := jmc$discard_all_output;
    ELSEIF pvt [p$output_disposition].value^.keyword_value = 'DISCARD_STANDARD_OUTPUT' THEN
      job_submission_options^ [5].output_disposition.key := jmc$discard_standard_output;
    ELSEIF pvt [p$output_disposition].value^.keyword_value = 'LOCAL' THEN
      job_submission_options^ [5].output_disposition.key := jmc$local_output_disposition;
    ELSEIF pvt [p$output_disposition].value^.keyword_value = 'PRINTER' THEN
      job_submission_options^ [5].output_disposition.key := jmc$normal_output_disposition;
    ELSEIF pvt [p$output_disposition].value^.keyword_value = 'WAIT_QUEUE' THEN
      job_submission_options^ [5].output_disposition.key := jmc$wait_queue_path;
      job_submission_options^ [5].output_disposition.wait_queue_path := NIL;
    IFEND;

    job_submission_options^ [6].key := jmc$remote_host_directive;
    PUSH job_submission_options^ [6].remote_host_directive;
    job_submission_options^ [6].remote_host_directive^.size := STRLENGTH (pvt [p$remote_host_directive]
          .value^.string_value^);
    job_submission_options^ [6].remote_host_directive^.parameters := pvt [p$remote_host_directive].value^
          .string_value^;

    IF pvt [p$user_job_name].specified THEN
      job_submission_options^ [7].key := jmc$user_job_name;
      job_submission_options^ [7].user_job_name := pvt [p$user_job_name].value^.name_value;
    ELSE
      job_submission_options^ [7].key := jmc$null_attribute;
    IFEND;

{  submit the rhf structured file to the system.

    jmp$submit_job (job_file_name, job_submission_options, system_supplied_name, status);

{  return the rhf structured file.

    amp$return (job_file_name, ignore_status);

    IF status.normal THEN

{  return the system_job_name to the user

      IF pvt [p$system_job_name].specified THEN
        PUSH system_job_name;
        system_job_name^.kind := clc$name;
        system_job_name^.name_value := system_supplied_name;
        clp$change_variable (pvt [p$system_job_name].variable^, system_job_name, status);
      IFEND;
    IFEND;

    osp$disestablish_cond_handler;

  PROCEND nfp$_submit_multi_record_job;
?? OLDTITLE ??
MODEND nfm$submit_multi_record_job;
