?? RIGHT := 110 ??
MODULE iim$get;
?? TITLE := 'MODULE iim$get' ??

?? PUSH (LISTEXT := OFF) ??
*copyc amt$file_byte_address
*copyc bat$task_file_table
*copyc bav$last_tft_entry
*copyc bav$task_file_table
*copyc osv$170_os_type
*copyc iik$keypoints
*copyc amt$file_position
*copyc amt$skip_option
*copyc amc$fap_request_codes
*copyc amt$max_record_length
*copyc amt$transfer_count
*copyc ame$terminal_validation_errors
*copyc amt$working_storage_length
*copyc amp$put_next
*copyc amp$set_file_instance_abnormal
*copyc clp$get_system_file_id
*copyc clc$standard_file_names
*copyc fsp$open_file
*copyc cle$unseen_mail_condition
*copyc osc$unseen_mail_condition
*copyc osc$job_recovery_condition_name
*copyc ife$error_codes
*copyc ifp$fap_control
*copyc ifp$immediate_attribute_flush
*copyc iit$connection_description
*copyc iip$build_term_char_values
*copyc iip$clear_lock
*copyc iip$flush
*copyc iiv$interactive_terminated
*copyc iip$put
*copyc iip$report_status_error
*copyc iip$set_lock
*copyc iiv$int_task_open_file_count
*copyc iiv$connection_desc_ptr
*copyc iip$update_open_desc_attributes
*copyc jmp$change_dispatching_prior_r1
*copyc jmp$select_reset_disp_pr_r2
*copyc jmt$dispatching_control_info
*copyc jmv$jcb
*copyc jmv$system_job_ssn
*copyc oss$job_paged_literal
*copyc ost$status
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc pmp$continue_to_cause
*copyc pmp$ready_task
*copyc pmp$log
*copyc osp$establish_condition_handler
*copyc osp$fetch_locked_variable
*copyc osp$initialize_signature_lock
*copyc osp$test_sig_lock
*copyc iip$build_super_msg_skeleton
*copyc mlp$receive_message
*copyc iip$report_unhandled_super_msg
*copyc iip$send_to_pass_on
*copyc pmp$long_term_wait
*copyc mld$memory_link_declarations
*copyc tmc$wait_times
*copyc pmp$exit
*copyc osp$disestablish_cond_handler
*copyc clp$get_time_string
*copyc pmp$get_job_names
*copyc tmv$null_global_task_id
?? POP ??

PROCEDURE [XREF] iip$disconnect_job (end_connection: boolean;
      start_new_job: boolean;
  VAR status: ost$status);

?? NEWTITLE := 'PROCEDURE iip$get', EJECT ??

  PROCEDURE [XDCL, #GATE] iip$get (file_id: amt$file_identifier;
        open_file_desc_pointer: ^iit$open_file_description;
        operation: amt$fap_operation;
        working_storage_area: ^cell;
        working_storage_length: amt$working_storage_length;
        record_length: ^amt$max_record_length;
        transfer_count: ^amt$transfer_count;
        byte_address: ^amt$file_byte_address;
        file_position: ^amt$file_position;
        skip_option: amt$skip_option;
    VAR status: ost$status);

    PROCEDURE get;

    VAR
      file_identifier: amt$file_identifier,
      file_id_is_valid: boolean,
      file_instance: ^bat$task_file_entry,
      warning_message: [STATIC, READ, oss$job_paged_literal] string (35) :=
            ' TERMINAL TIMEOUT IN 30 SECONDS.' CAT $char(7) CAT $char(13) CAT $char(10),
      timeout_message: string (80),
      str: ost$string,
      user_supplied_name: jmt$user_supplied_name,
      system_supplied_name: jmt$system_supplied_name,
      saved_attributes: iit$connection_attributes,
      saved_build_msg: boolean,
      saved_effectors: boolean,
      current_transfer_count: amt$transfer_count,
      move_length: iit$block_size,
      reissue_read_after_skipping: boolean,
      null_dispatching_info: jmt$dispatching_control_info,
      first_time: boolean,
      working_storage_array_pointer: ^array [0 .. iic$max_record_length] of char,
      skip_upline_block,
      input_timeout_started, { indicates whether or not the input timeout countdown has begun }
      disconnect_timeout_started, { indicates whether or not the disconnect timeout countdown has begun }
      timeout_warning_posted,
      prompt_sent: boolean,
      put_byte_address: amt$file_byte_address,
      start, { the start time for timeout countdowns }
      short_wait_count: integer,
      prompt_block_number: integer,
      get_lock_set: boolean,
      mult,
      igtid,
      expected_wait,
      limit,
      j,
      i: integer,
      input_cell_ptr,
      output_cell_ptr: ^iit$nibble_string,
      output_supervisory_message: iit$output_supervisory_message,
      c170_upline_message_length: mlt$message_length,
      c170_upline_super_msg_pointer: ^iit$input_supervisory_message,
      arb: mlt$arbitrary_info,
      san: mlt$application_name,
      gtid: ost$global_task_id,
      xcb: ^ost$execution_control_block,
      lock_status: ost$signature_lock_status,
      open_file_dsc_pointer: ^iit$open_file_description,
      local_status: ost$status;

?? NEWTITLE := 'FUNCTION eoi', EJECT ??

      FUNCTION eoi: boolean;

        { If the data just received is equal to the end_of_information
        { attribute
        { for this file instance return with eoi set to TRUE; otherwise, FALSE.

        VAR
          local_stat: ost$status,
          end_of_info: boolean,
          wsa_pointer: ^string (ifc$max_end_of_information_size);

        IF open_file_desc_pointer^.attributes.end_of_information.
          value.value (1, open_file_desc_pointer^.attributes.
          end_of_information.value.size) = $char(13) THEN
          IF iiv$get_info.record_length = 0 THEN
            eoi := true;
          ELSE
            eoi := false;
          IFEND;
        ELSE
          end_of_info := (working_storage_area <> NIL) AND
            (open_file_desc_pointer^.attributes.end_of_information.value.
            size <> 0) AND (open_file_desc_pointer^.attributes.
            input_editing_mode.value = ifc$normal_edit) AND
            (iiv$get_info.record_length =
            open_file_desc_pointer^.attributes.end_of_information.value.
            size);

          IF end_of_info THEN
            wsa_pointer := working_storage_area;
            end_of_info := (wsa_pointer^ (1, iiv$get_info.
              record_length) = open_file_desc_pointer^.attributes.
              end_of_information.value.value (1, open_file_desc_pointer^.
              attributes.end_of_information.value.size));
          IFEND;
          eoi := end_of_info;
        IFEND;
      FUNCEND eoi;
?? OLDTITLE ??
?? NEWTITLE := 'PROCEDURE send_prompt', EJECT ??

    PROCEDURE send_prompt (VAR status: ost$status);

      VAR
        file_identifier: amt$file_identifier,
        file_id_is_valid: boolean,
        file_instance: ^bat$task_file_entry,
        prompt_file_no_format_effectors: boolean,
        prompt_string_start_index: 1 .. ifc$max_prompt_string_size,
        iiv$begin_absentee : [xdcl] boolean,
        format_effector_null_prompt: char,
        put_length: amt$working_storage_length,
        open_file_dsc_pointer: ^iit$open_file_description,
        put_byte_address: amt$file_byte_address;

      status.normal := TRUE;

{ Ensure that the prompt file is open.

   IF open_file_desc_pointer^.attributes.prompt_file_identifier.value.ordinal = 0 THEN
     fsp$open_file (open_file_desc_pointer^.attributes.prompt_file.value, amc$record, NIL, NIL, NIL, NIL,
        NIL, open_file_desc_pointer^.attributes.prompt_file_identifier.value, status);
        open_file_desc_pointer^.attributes.prompt_file_identifier.source := ifc$os_default;
        IF NOT status.normal THEN
          RETURN;
        IFEND;
      IFEND;

      put_length := 0;
      prompt_string_start_index := 1;
      iiv$put_info.build_msg_block := TRUE;

      iiv$begin_absentee := TRUE;
      IF open_file_desc_pointer^.attributes.input_timeout.value AND
        (open_file_desc_pointer^.attributes.input_timeout_length.value = 0) THEN
        iiv$begin_absentee := FALSE;
      IFEND;

      IF (open_file_desc_pointer^.attributes.input_editing_mode.value = ifc$normal_edit) AND
            (open_file_desc_pointer^.attributes.prompt_string.value.size <> 0) THEN

      { Determine whether or not the prompt file has format effectors.

        file_identifier := open_file_desc_pointer^.attributes.
          prompt_file_identifier.value;
*copy bai$validate_file_identifier
*copy iii$fetch_open_file_desc_ptr
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        prompt_file_no_format_effectors := NOT open_file_dsc_pointer^.
          format_effectors;

        put_length := open_file_desc_pointer^.attributes.prompt_string.value.size;

{ Discard the format effector of the prompt string if at mid record.

        IF (open_file_desc_pointer^.attributes.prompt_string.value.size <> 0) AND
              (NOT prompt_file_no_format_effectors) AND (iiv$put_info.
              last_term_option <> amc$terminate) THEN
          prompt_string_start_index := 2;
          put_length := open_file_desc_pointer^.attributes.prompt_string.value.size -
                1;
        IFEND;

{ Output the prompt string.

        open_file_dsc_pointer^.attributes.trans_character_mode.value :=
          ifc$no_trans_char;

        IF (put_length = 0) AND (NOT prompt_file_no_format_effectors) AND
              (iiv$put_info.last_term_option = amc$terminate) THEN
          format_effector_null_prompt := ifc$pre_print_no_positioning;
          put_length := 1;
          iip$put (open_file_desc_pointer^.attributes.prompt_file_identifier.value,
                open_file_dsc_pointer,
                amc$put_partial_req, ^format_effector_null_prompt, put_length,
                ^put_byte_address, amc$terminate, status);
        ELSE
          iip$put (open_file_desc_pointer^.attributes.prompt_file_identifier.value,
                open_file_dsc_pointer,
                amc$put_partial_req, ^open_file_desc_pointer^.attributes.prompt_string.value.
                value (prompt_string_start_index, 1), put_length,
                ^ put_byte_address, amc$terminate, status);
        IFEND;

        iiv$put_info.build_msg_block := FALSE;

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

{ Output an iic$last_block for the get file id.
      iiv$put_info.term_char_null := TRUE;

      iip$put (file_id, open_file_desc_pointer, amc$put_partial_req,
            ^open_file_desc_pointer^.attributes.prompt_string.value.value
            (prompt_string_start_index, 1), 0, ^put_byte_address,
            amc$terminate, status);

      iiv$put_info.term_char_null := FALSE;
      iiv$put_info.build_msg_block := FALSE;

      IF NOT status.normal THEN
        RETURN;
      IFEND;

      iip$flush (file_id, open_file_desc_pointer, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

    PROCEND send_prompt;

?? TITLE := 'PROCEDURE handle_break', EJECT ??

    PROCEDURE handle_break (cond: pmt$condition;
          cd: ^pmt$condition_information;
          sa: ^ost$stack_frame_save_area;
      VAR ch_status: ost$status);

      VAR
        break_abn: integer,
        local_status: ost$status;

{ return to screen with abnormal status

      IF cond.selector = pmc$user_defined_condition THEN
        IF cond.user_condition_name = osc$job_recovery_condition_name THEN
          pmp$continue_to_cause (pmc$execute_standard_procedure, ch_status);
          RETURN;
        ELSEIF cond.user_condition_name = osc$unseen_mail_condition THEN
          osp$set_status_condition (cle$unseen_mail_condition, status);
          pmp$continue_to_cause (pmc$execute_standard_procedure, ch_status);
          EXIT iip$get;
        IFEND;
      IFEND;

      IF (cond.selector = ifc$interactive_condition) OR
          (cond.selector = pmc$block_exit_processing) THEN
        break_abn := iiv$break_abn;
        IF get_lock_set THEN
          iiv$get_info.file_position := amc$eor;
          iip$clear_lock (iiv$get_lock, local_status);
          get_lock_set := FALSE;
        IFEND;

        IF (cond.selector = ifc$interactive_condition) THEN
          CASE cond.interactive_condition OF
          = ifc$pause_break =
            osp$set_status_condition (ife$pause_break_received, status);
          = ifc$terminate_break =
            osp$set_status_condition (ife$terminate_break_received, status);
          = ifc$terminal_connection_broken =
            osp$set_status_condition (ife$connection_break_disconnect, status);
          = ifc$job_reconnect =
            osp$set_status_condition (ife$terminal_reconnected_to_job, status);
          ELSE
            osp$set_status_abnormal (ifc$interactive_facility_id, 0,
              'unknown interactive condition encountered', status);
          CASEND;
          pmp$continue_to_cause (pmc$execute_standard_procedure, ch_status);
          EXIT iip$get;
        ELSE
          {Do nothing for block exit
          RETURN;
        IFEND;
      IFEND;

      pmp$continue_to_cause (pmc$execute_standard_procedure, ch_status);

    PROCEND handle_break;
?? TITLE := 'PROCEDURE handle_exit', EJECT ??

{ This code has been disabled to prevent the overhead associated with
{ block exit handling.
{
{   PROCEDURE handle_exit (cond: pmt$condition;
{         cd: ^pmt$condition_information;
{         sa: ^ost$stack_frame_save_area;
{     VAR ch_status: ost$status);
{
{     VAR
{       local_status: ost$status;
{
{     IF get_lock_set THEN
{       iiv$get_info.file_position := amc$eor;
{       iip$clear_lock (iiv$get_lock, local_status);
{       get_lock_set := FALSE;
{     IFEND;
{     pmp$continue_to_cause (pmc$execute_standard_procedure, local_status);
{     ch_status.normal := TRUE;
{
{   PROCEND handle_exit;

?? OLDTITLE, EJECT ??

    #KEYPOINT (osk$entry, 0, iik$get);

{ any gets while iiv$interactive_terminated is true cause exit.
    IF iiv$interactive_terminated THEN
      osp$set_status_condition (ife$abort_get, status);
      #KEYPOINT (osk$exit, 0, iik$get);
      pmp$exit (status);
    IFEND;
    prompt_sent := FALSE;
    get_lock_set := FALSE;
    skip_upline_block := FALSE;
    reissue_read_after_skipping := FALSE;

{ The following procedure call causes the jobs priority to be reset. It is
{ support code for DYNAMIC DISPATCHING. This procedure calls a ring 1 procedure
{ which stores the global_taskid of this task (the interactive task) in the
{ IJL entry of the job. When the task is next readied, the priority of the job
{ will be reset, and the taskid in the IJL entry will be set to null. If
{ we exit this procedure with the taskid still in the IJL entry, the priority
{ of the job will be immediately reset. The situation will occur if the user
{ is typing ahead.

      jmp$select_reset_disp_pr_r2;

{   Protect the get lock with a handler for interactive conditions to
{   insure that they are recognized and the get lock gets cleared.

    osp$establish_condition_handler (^handle_break, TRUE);
    osp$test_sig_lock (iiv$get_lock, lock_status);

    IF lock_status = osc$sls_locked_by_another_task THEN

{     Determine the task which set the lock and clear its lock if the
{     the task has terminated.

      osp$fetch_locked_variable (iiv$get_lock.lock_id, igtid);

    /assemble_gtid/
      BEGIN
        mult := 1;
        FOR i := 1 TO #SIZE (gtid.seqno) DO
          mult := mult * 256;
        FOREND;

        IF (igtid DIV mult) > UPPERVALUE (gtid.index) THEN
          EXIT /assemble_gtid/;
        IFEND;
        gtid.index := igtid DIV mult;
        IF (igtid MOD mult) > UPPERVALUE (gtid.seqno) THEN
          EXIT /assemble_gtid/;
        IFEND;
        gtid.seqno := igtid MOD mult;
        pmp$ready_task (gtid, status);
        IF  NOT status.normal THEN
          osp$initialize_signature_lock (iiv$get_lock, status);
        IFEND;
      END /assemble_gtid/;

    ELSEIF lock_status = osc$sls_locked_by_current_task THEN

{     Some sort of unintended recursion has occured due to break, escape,
{     task/job termination, etc.  RETURN with normal status.

      status.normal := TRUE;
      #KEYPOINT (osk$exit, 0, iik$get);
      osp$disestablish_cond_handler;
      RETURN;
    IFEND;

    iip$set_lock (iiv$get_lock, osc$wait, status);
    IF NOT status.normal THEN
      #KEYPOINT (osk$exit, 0, iik$get);
      osp$disestablish_cond_handler;
      RETURN;
    IFEND;
    get_lock_set := TRUE;
    working_storage_array_pointer := NIL;

  /do_it_all_again/
    WHILE TRUE DO

      status.normal := TRUE;

{     Set up for data transfer.

      IF skip_option = amc$skip_to_eor THEN
        IF iiv$get_info.file_position = amc$mid_record THEN
          iiv$get_info.position_in_block := 1;
          IF iiv$get_info.block_type = iic$last_block THEN
            skip_upline_block := FALSE;
            iiv$get_info.file_position := amc$eor;
            reissue_read_after_skipping := TRUE;
          ELSE
            skip_upline_block := TRUE;
          IFEND;
        IFEND;
      IFEND;

{     Update the terminal attributes of the open file description if they might
{     have changed.

      IF open_file_desc_pointer^.attributes_cycle <> open_file_desc_pointer^.
            connection_desc_pointer^.attributes_cycle THEN
        iip$update_open_desc_attributes (file_id, open_file_desc_pointer,
              operation, status);
        IF NOT status.normal THEN
          iip$clear_lock (iiv$get_lock, local_status);
          #KEYPOINT (osk$exit, 0, iik$get);
          osp$disestablish_cond_handler;
          RETURN;
        IFEND;
      IFEND;

      IF (skip_option = amc$skip_to_eor) OR (iiv$get_info.file_position <>
            amc$mid_record) THEN
        IF NOT prompt_sent THEN
          send_prompt (status);
          prompt_sent := TRUE;
          prompt_block_number := iiv$put_info.block_number;
          IF NOT status.normal THEN
            iip$clear_lock (iiv$get_lock, local_status);
            #KEYPOINT (osk$exit, 0, iik$get);
            osp$disestablish_cond_handler;
            RETURN;
          IFEND;
        IFEND;
      IFEND;

    { Detect context switching and, if needed, blank the screen.

      IF (iiv$previous_mode = iic$screen) AND
            ((open_file_desc_pointer^.terminal_mode = iic$line) OR (file_id.ordinal <>
            iiv$previous_file_id.ordinal)) THEN
        iiv$previous_mode := iic$line;
        IF NOT iiv$previous_blank_flag THEN
          iiv$previous_blank_flag := TRUE;
          saved_attributes := open_file_desc_pointer^.attributes;
          saved_build_msg := iiv$put_info.build_msg_block;
          saved_effectors := open_file_desc_pointer^.format_effectors;
          open_file_desc_pointer^.attributes := iiv$previous_connection_attr;
          open_file_desc_pointer^.format_effectors := FALSE;
          iiv$put_info.build_msg_block := FALSE;
          iip$build_term_char_values (open_file_desc_pointer);
          iip$put (file_id, open_file_desc_pointer, amc$put_next_req,
            #LOC (iiv$screen_clear_string.value), iiv$screen_clear_string.size,
            ^put_byte_address, amc$terminate, status);
          open_file_desc_pointer^.attributes := saved_attributes;
          open_file_desc_pointer^.format_effectors := saved_effectors;
          iiv$put_info.build_msg_block := saved_build_msg;
          iip$build_term_char_values (open_file_desc_pointer);
        IFEND;
      IFEND;

      iiv$previous_blank_flag := FALSE;
      IF open_file_desc_pointer^.terminal_mode = iic$line THEN
        iiv$previous_mode := iic$line;
      IFEND;
      iiv$previous_operation := operation;
      iiv$previous_file_id := file_id;

      IF iiv$get_info.file_position <> amc$mid_record THEN
        iiv$get_info.record_length := 0;
        iiv$get_info.transfer_count := 0;
        iiv$get_info.position_in_block := 1;
      IFEND;


      current_transfer_count := 0;
      first_time := true;
    /transfer_data_to_user/
      WHILE TRUE DO

      input_timeout_started := FALSE;
      disconnect_timeout_started := FALSE;
      timeout_warning_posted := FALSE;

      /read_upline_data/
        WHILE TRUE DO

          IF iiv$get_info.position_in_block = 1 THEN

            iiv$get_info.queued_data_length := 0;
            expected_wait := iic$user_time_delay;

{           Build read request.
            IF NOT first_time OR (iiv$get_info.block_type <> iic$last_block)
                  OR reissue_read_after_skipping THEN
              iip$build_super_msg_skeleton (^output_supervisory_message,
                    iic$sm_read_request, iic$l_read_request);
              output_supervisory_message.read_request.connection_number :=
                    iiv$job_connection;
              output_supervisory_message.read_request.begin_absentee := TRUE;
              output_supervisory_message.read_request.notify_if_absentee_started
                    := TRUE;

              IF open_file_desc_pointer^.attributes.input_timeout.value AND
                    (open_file_desc_pointer^.attributes.input_timeout_length.value = 0) THEN
                output_supervisory_message.read_request.begin_absentee := FALSE;
              IFEND;

  {           Send read request to Pass-On.

              iip$send_to_pass_on (iiv$int_application_name, #LOC
                    (output_supervisory_message), (iic$l_read_request + 1) * 8,
                    iic$output_supervisory_message, status);

              IF NOT status.normal THEN
                iip$clear_lock (iiv$get_lock, local_status);
                #KEYPOINT (osk$exit, 0, iik$get);
                osp$disestablish_cond_handler;
                RETURN;
              IFEND;
            IFEND;
            first_time := false;
            reissue_read_after_skipping := FALSE;
            short_wait_count := 0;

          /wait_receive/
            WHILE TRUE DO

{             Receive upline block from Pass-On.

              mlp$receive_message (iiv$int_application_name, arb, NIL, #LOC
                    (iiv$upline_data_buffer_ptr^), c170_upline_message_length,
                    #SIZE (iiv$upline_data_buffer_ptr^), 0, san, status);
              IF NOT status.normal THEN
                CASE status.condition OF
                = mlc$busy_interlock, mlc$receive_list_index_invalid =
                  pmp$long_term_wait (expected_wait, expected_wait);
                  IF iiv$abort_get THEN
                    iiv$abort_get := FALSE;
                    iip$clear_lock (iiv$get_lock, local_status);
                    #KEYPOINT (osk$exit, 0, iik$get);
                    osp$set_status_condition (ife$abort_get, status);
                    osp$disestablish_cond_handler;
                    RETURN;
                  IFEND;

                  IF input_timeout_started THEN
                    mlp$receive_message (iiv$int_application_name, arb, NIL, #LOC
                          (iiv$upline_data_buffer_ptr^), c170_upline_message_length,
                          #SIZE (iiv$upline_data_buffer_ptr^), 0, san, status);
                    IF NOT status.normal THEN

                      expected_wait := open_file_desc_pointer^.
                      attributes.input_timeout_length.value -
                            ((#free_running_clock (0) - start) DIV 1000);
                      IF expected_wait > 0 THEN
                        CYCLE /wait_receive/;
                      IFEND;

                      { Build and send a LST/OFF/R to PASSON.

                      iip$build_super_msg_skeleton (^output_supervisory_message,
                            iic$sm_list_off, iic$l_list_off);
                      output_supervisory_message.list_off.connection_number := iiv$job_connection;
                      iip$send_to_pass_on (iiv$int_application_name, #LOC (output_supervisory_message),
                            (iic$l_list_off + 1) * 8, iic$output_supervisory_message, status);
                      IF NOT status.normal THEN
                        iip$clear_lock (iiv$get_lock, local_status);
                        #KEYPOINT (osk$exit, 0, iik$get);
                        osp$disestablish_cond_handler;
                        RETURN;
                      IFEND;

                      { If input_timeout_length <> 0 and input_timeout_purge then build and
                      { send a FC/BRK/R to PASSON.

                      IF open_file_desc_pointer^.attributes.input_timeout_purge.value AND
                            (open_file_desc_pointer^.attributes.input_timeout_length.value <> 0) THEN
                        iip$build_super_msg_skeleton (^output_supervisory_message,
                              iic$sm_break, iic$l_break);
                        output_supervisory_message.break.connection_number := iiv$job_connection;
                        iip$send_to_pass_on (iiv$int_application_name,
                              #LOC (output_supervisory_message), (iic$l_break + 1) * 8,
                              iic$output_supervisory_message, status);
                        IF NOT status.normal THEN
                          iip$clear_lock (iiv$get_lock, local_status);
                          #KEYPOINT (osk$exit, 0, iik$get);
                          osp$disestablish_cond_handler;
                          RETURN;
                        IFEND;
                      IFEND;

{ Decrement the time left before the disconnect timeout limit expires by the Input_Timeout_Length.

                      iiv$terminal_timeout_limit_left := iiv$terminal_timeout_limit_left -
                            open_file_desc_pointer^.attributes.input_timeout_length.value;

                      osp$set_status_condition (ife$input_timeout_exceeded, status);
                      iip$clear_lock (iiv$get_lock, local_status);
                      #KEYPOINT (osk$exit, 0, iik$get);
                      osp$disestablish_cond_handler;
                      RETURN;

                    IFEND;
                  ELSEIF disconnect_timeout_started AND (iiv$terminal_timeout_limit <> tmc$infinite_wait) THEN
                    mlp$receive_message (iiv$int_application_name, arb, NIL, #LOC
                          (iiv$upline_data_buffer_ptr^), c170_upline_message_length,
                          #SIZE (iiv$upline_data_buffer_ptr^), 0, san, status);
                    IF NOT status.normal THEN

{ Recalculate the disconnect wait time.  Wait for input again if the disconnect wait time is not expired.

                      expected_wait := iiv$terminal_timeout_limit_left -
                            ((#free_running_clock (0) - start) DIV 1000);
                      IF expected_wait > 0 THEN
                        CYCLE /wait_receive/;
                      IFEND;

                      IF timeout_warning_posted THEN

{ Display time and job name in the message accompanying the job disconnection and the job log.

                        clp$get_time_string (str, status);
                        timeout_message (1, 1) := ' ';
                        timeout_message (2, str.size) := str.value (1, str.size);
                        timeout_message (str.size + 2, 24) := ' TERMINAL TIMEOUT.  JOB ';
                        pmp$get_job_names (user_supplied_name, system_supplied_name, status);
                        timeout_message (str.size + 26, 19) := system_supplied_name;
                        timeout_message (str.size + 46, 12) :=
                              ' DETACHED.' CAT $char(13) CAT $char (10);
                        pmp$log (timeout_message (str.size + 3, 54), status);
                        iip$put (file_identifier, open_file_dsc_pointer, amc$put_next_req,
                              #LOC (timeout_message), str.size + 57, byte_address, amc$terminate, status);
                        iip$flush (file_identifier, open_file_dsc_pointer, status);
                        iip$disconnect_job (iic$end_connection, iic$dont_start_new_job, status);
                        IF NOT status.normal THEN
                          #KEYPOINT (osk$exit, 0, iik$get);
                          RETURN;
                        IFEND;
                      ELSE { timeout_warning_posted }

  { Output the timeout warning message to the terminal and job log and wait 2 minutes more for input data.

                        clp$get_system_file_id (clc$job_output, file_identifier, status);
                        IF NOT status.normal THEN
                          #KEYPOINT (osk$exit, 0, iik$get);
                          RETURN;
                        IFEND;
*copy bai$validate_file_identifier
*copy iii$fetch_open_file_desc_ptr
                        IF NOT status.normal THEN
                          #KEYPOINT (osk$exit, 0, iik$get);
                          RETURN;
                        IFEND;
                        pmp$log (warning_message (1, 32), status);
                        iip$put (file_identifier, open_file_dsc_pointer, amc$put_next_req,
                              ^warning_message, 35, byte_address, amc$terminate, status);
                        IF NOT status.normal THEN
                          #KEYPOINT (osk$exit, 0, iik$get);
                          RETURN;
                        IFEND;
                        iip$flush (file_identifier, open_file_dsc_pointer, status);
                        IF NOT status.normal THEN
                          #KEYPOINT (osk$exit, 0, iik$get);
                          RETURN;
                        IFEND;
                        timeout_warning_posted := TRUE;
                        expected_wait := 30000;  { thirty seconds in terms of milliseconds }
                        iiv$terminal_timeout_limit_left := 30000;
                        start := #free_running_clock (0);
                        CYCLE /wait_receive/;
                      IFEND; { timeout_warning_posted }
                    ELSE { status.normal from mlp$receive_message after disconnect-timeout started.
                      IF iiv$upline_data_buffer_ptr^.header.block_type <> iic$supervisory_block THEN
                        iiv$terminal_timeout_limit_left := iiv$terminal_timeout_limit;
                      IFEND;
                    IFEND; { status.normal from mlp$receive_message after disconnect-timeout started.
                  ELSE { NOT input_timeout_started--NOT disconnect_timeout_started }
                    short_wait_count := short_wait_count + 1;
                    IF short_wait_count > 10 THEN
{ Force long waits for either the disconnect timeout limit or infinite.
                      IF iiv$terminal_timeout_limit <> tmc$infinite_wait THEN
                        expected_wait := iiv$terminal_timeout_limit_left - (10 * iic$user_time_delay);
                        IF expected_wait < 0 THEN
                          expected_wait := 0;
                        IFEND;
                        disconnect_timeout_started := TRUE;
                        start := #free_running_clock (0);
                      ELSE
                        expected_wait := tmc$infinite_wait;
                      IFEND;
                    IFEND; { short_wait_count > 10 }
                    CYCLE /wait_receive/;
                  IFEND; { NOT input_timeout_started--NOT disconnect_timeout_started }
                ELSE
                  iip$clear_lock (iiv$get_lock, local_status);
                  #KEYPOINT (osk$exit, 0, iik$get);
                  osp$disestablish_cond_handler;
                  RETURN;
                CASEND;
              ELSE { status.normal }
                IF iiv$upline_data_buffer_ptr^.header.block_type <> iic$supervisory_block THEN
                  iiv$terminal_timeout_limit_left := iiv$terminal_timeout_limit;
                IFEND;
              IFEND; { status.normal }

              IF iiv$upline_data_buffer_ptr^.header.block_type =
                    iic$supervisory_block THEN

                IF input_timeout_started THEN
                  expected_wait := open_file_desc_pointer^.attributes.input_timeout_length.value -
                        (#free_running_clock (0) - start);
                ELSEIF disconnect_timeout_started AND (iiv$terminal_timeout_limit <> tmc$infinite_wait) THEN
                  expected_wait := iiv$terminal_timeout_limit_left - ((#free_running_clock (0) - start)
                        DIV 1000);
                IFEND;
                IF expected_wait < 0 THEN
                  expected_wait := 0;
                IFEND;

                c170_upline_super_msg_pointer := #LOC (iiv$upline_data_buffer_ptr^);
                CASE c170_upline_super_msg_pointer^.message_type OF
                = iic$sm_read_rejected =
                  pmp$long_term_wait (iic$user_time_delay, iic$user_time_delay);
                  IF iiv$abort_get THEN
                    iiv$abort_get := FALSE;
                    iip$clear_lock (iiv$get_lock, local_status);
                    #KEYPOINT (osk$exit, 0, iik$get);
                    osp$set_status_condition (ife$abort_get, status);
                    osp$disestablish_cond_handler;
                    RETURN;
                  IFEND;
                  CYCLE /read_upline_data/;
                = iic$sm_define_term_char_n, iic$sm_cdcnet_define_term_chr_n,
                  iic$sm_cdcnet_unsolct_term_char =
{                 ignore these
                  CYCLE /read_upline_data/;
                = iic$sm_absentee_begun =

                  IF iiv$terminal_timeout_limit <> tmc$infinite_wait THEN
                    expected_wait := iiv$terminal_timeout_limit_left;
                    disconnect_timeout_started := TRUE;
                  ELSE
                    expected_wait := tmc$infinite_wait;
                  IFEND;

                  IF open_file_desc_pointer^.attributes.input_timeout.value THEN
                    IF expected_wait > open_file_desc_pointer^.attributes.input_timeout_length.value THEN
                      expected_wait := open_file_desc_pointer^.attributes.input_timeout_length.value;
                      input_timeout_started := TRUE;
                      disconnect_timeout_started := FALSE;
                    IFEND;
                  IFEND;
                  start := #free_running_clock (0);
                  CYCLE /wait_receive/;
                ELSE
                  iip$report_unhandled_super_msg (c170_upline_super_msg_pointer^);
                  CYCLE /read_upline_data/;
                CASEND;
              IFEND;

              EXIT /wait_receive/;
            WHILEND /wait_receive/;

            IF iiv$upline_data_buffer_ptr^.header.block_type = iic$null_block THEN
              IF open_file_desc_pointer^.attributes.input_timeout.value AND
                    (open_file_desc_pointer^.attributes.input_timeout_length.value = 0) THEN
                osp$set_status_condition (ife$no_data_available, status);
                iip$clear_lock (iiv$get_lock, local_status);
                #KEYPOINT (osk$exit, 0, iik$get);
                osp$disestablish_cond_handler;
                RETURN;
              IFEND;
              CYCLE /read_upline_data/;
            IFEND;

            iiv$get_info.block_type := iiv$upline_data_buffer_ptr^.header.
                  block_type;
            iiv$get_info.record_length := iiv$get_info.record_length +
                  iiv$upline_data_buffer_ptr^.header.text_length;
            iiv$get_info.queued_data_length := iiv$get_info.queued_data_length
                  + iiv$upline_data_buffer_ptr^.header.text_length;
            iiv$get_info.cancel_input := iiv$upline_data_buffer_ptr^.header.
                  cancel;
{           Check to see if transparent mode has been dropped with this input block.

            IF (open_file_desc_pointer^.connection_desc_pointer^.
                  active_term_char_values [iic$key_trans_input_mode] <> 0) AND
                  (NOT iiv$upline_data_buffer_ptr^.header.transparent) THEN
              osp$set_status_abnormal (ifc$interactive_facility_id, ife$xpt_mode_drop_unexpected,
                    '', status);
              open_file_desc_pointer^.connection_desc_pointer^.
                    active_term_char_values [iic$key_trans_input_mode] := 0;
              open_file_desc_pointer^.connection_desc_pointer^.
                    active_term_char_values [iic$key_trans_input_type] := iic$single_message;
              open_file_desc_pointer^.connection_desc_pointer^.
                    term_char_values [iic$key_trans_input_mode] := 0;
              open_file_desc_pointer^.connection_desc_pointer^.
                    term_char_values [iic$key_trans_input_type] := iic$single_message;
            IFEND;

          IFEND; { iiv$get_info.position_in_block = 1 }

          IF (iiv$upline_data_buffer_ptr^.header.text_length <> 0) AND
                (working_storage_length <> 0) THEN
            move_length := (iiv$upline_data_buffer_ptr^.header.text_length + 1)
                  - iiv$get_info.position_in_block;
            IF move_length + current_transfer_count > working_storage_length
                  THEN
              move_length := working_storage_length - current_transfer_count;
            IFEND;

            { Copy upline data into the user's working storage area.

            input_cell_ptr := #LOC (iiv$upline_data_buffer_ptr^.data);
            output_cell_ptr := working_storage_area;

            j := current_transfer_count * 2;
            IF osv$170_os_type = osc$ot7_dual_state_nos_be THEN
              i := (16 * iiv$get_info.position_in_block - 11) DIV 5;
            ELSE
              i := (32 * iiv$get_info.position_in_block - 16) DIV 15;
            IFEND;
            limit := move_length * 2;

          /move_half_bytes/
            WHILE limit <> 0 DO
              IF i MOD 16 = 0 THEN
                i := i + 1;
              IFEND;
              IF osv$170_os_type = osc$ot7_dual_state_nos_be THEN
              output_cell_ptr^ [j] := input_cell_ptr^ [i + 1];
              output_cell_ptr^ [j + 1] := input_cell_ptr^ [i + 2];
              j := j + 2;
              i := i + 3;
              limit := limit - 2;
              ELSE
              output_cell_ptr^ [j] := input_cell_ptr^ [i];
              j := j + 1;
              i := i + 1;
              limit := limit - 1;
              IFEND;
            WHILEND /move_half_bytes/;

            iiv$get_info.position_in_block := iiv$get_info.position_in_block +
                  move_length;

            current_transfer_count := current_transfer_count + move_length;
            iiv$get_info.transfer_count := iiv$get_info.transfer_count +
                  move_length;
          IFEND; {(working_storage_length <> 0) AND (upline text length <> 0)

          IF (iiv$get_info.position_in_block > iiv$get_info.queued_data_length) THEN
            iiv$get_info.position_in_block := 1;
          IFEND;

          IF (iiv$upline_data_buffer_ptr^.header.block_type = iic$last_block)
                OR (iiv$upline_data_buffer_ptr^.header.cancel) OR
                (iiv$get_info.queued_data_length >= iic$max_cancellable_input)
                OR (current_transfer_count = working_storage_length)
                THEN
            EXIT /read_upline_data/;
          IFEND;

        WHILEND /read_upline_data/;

        IF skip_upline_block THEN
          CYCLE /do_it_all_again/;
        IFEND;

        IF (iiv$get_info.cancel_input) THEN
          iiv$get_info.file_position := amc$eor;
          iiv$get_info.position_in_block := 1;
          iiv$get_info.record_length := 0;
          iiv$get_info.transfer_count := 0;
          current_transfer_count := 0;
          CYCLE /transfer_data_to_user/;
        IFEND;

        working_storage_array_pointer := working_storage_area;

        IF current_transfer_count = working_storage_length THEN
          EXIT /transfer_data_to_user/;
        IFEND;

        iiv$get_info.position_in_block := 1;

        IF iiv$get_info.block_type = iic$last_block THEN
          EXIT /transfer_data_to_user/;
        IFEND;

      WHILEND /transfer_data_to_user/;

{     Set proper post operation file position.

      IF (((iiv$get_info.position_in_block = 1) AND (iiv$get_info.block_type =
            iic$last_block)) OR (iiv$get_info.position_in_block - 1 =
            iiv$get_info.record_length)) THEN
        iiv$get_info.file_position := amc$eor;
      ELSE
        iiv$get_info.file_position := amc$mid_record;
      IFEND;

{     Detect input cancellation.

      IF (iiv$get_info.file_position = amc$eor) AND (iiv$get_info.cancel_input)
            AND (iiv$get_info.record_length > iic$max_cancellable_input) THEN
        amp$set_file_instance_abnormal (file_id, ame$max_cancellable_input,
              operation, '', status);
      IFEND;

      EXIT /do_it_all_again/;

    WHILEND /do_it_all_again/;


{   Return parameters to the caller.

    IF record_length <> NIL THEN
      record_length^ := iiv$get_info.record_length;
    IFEND;

    IF transfer_count <> NIL THEN
      transfer_count^ := current_transfer_count;
    IFEND;

    IF file_position <> NIL THEN
      file_position^ := iiv$get_info.file_position;
    IFEND;

    IF byte_address <> NIL THEN
      byte_address^ := 0;
    IFEND;

{   Check for end-of-information.

    IF eoi() THEN
      IF record_length <> NIL THEN
        record_length^ := 0;
      IFEND;
      IF transfer_count <> NIL THEN
        transfer_count^ := 0;
      IFEND;
      IF file_position <> NIL THEN
        file_position^ := amc$eoi;
      IFEND;
      IF byte_address <> NIL THEN
        byte_address^ := 0;
      IFEND;

      iiv$get_info.file_position := amc$eoi;

    IFEND; { Check for end-of-information. }

{   Save access information.

    open_file_desc_pointer^.last_get_put_operation := operation;
    open_file_desc_pointer^.last_access_operation := operation;
    open_file_desc_pointer^.previous_record_length := iiv$get_info.
          record_length;

{ Raise priority if it has not already been done.

    IF jmv$jcb.ijle_p^.interactive_task_gtid <> tmv$null_global_task_id THEN
      jmp$change_dispatching_prior_r1 (tmc$cpo_interactive_command, jmv$jcb.ijl_ordinal, jmv$jcb.system_name,
         null_dispatching_info, local_status);
    IFEND;

    iip$clear_lock (iiv$get_lock, local_status);

    #KEYPOINT (osk$exit, 0, iik$get);

    osp$disestablish_cond_handler;
  PROCEND get;


  {Call the inner procedure

    get;

  PROCEND iip$get;

MODEND iim$get;
