?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Job Management job monitor routines' ??
MODULE jmm$job_monitor;

{ PURPOSE:
{   This module contains the code for a job to begin and end from within its environment.
{ This module also contains some monitoring routines for the job.

?? NEWTITLE := 'Global Declarations Referenced by this Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc amt$fap_pointer
*copyc amt$file_attributes
*copyc amt$file_identifier
*copyc amt$local_file_name
*copyc avc$system_defined_limit_names
*copyc clc$standard_file_names
*copyc cle$ecc_file_reference
*copyc dfe$error_condition_codes
*copyc gft$system_file_identifier
*copyc dmt$class
*copyc jmc$job_management_id
*copyc jmc$system_family
*copyc jme$job_monitor_conditions
*copyc jme$user_requested_exit
*copyc jml$user_id
*copyc jmt$clock_time
*copyc jmt$display_message
*copyc jmt$job_resource_signal
*copyc jmt$job_statistics
*copyc jmt$sense_switch_signal
*copyc jmt$swap_file_user_info
*copyc jmt$system_supplied_name
*copyc jmt$user_supplied_name
*copyc jmv$xterm_job
*copyc mme$condition_codes
*copyc nat$wait_time
*copyc osc$dual_state_interactive
*copyc osc$timesharing
*copyc osc$timesharing_terminal_file
*copyc osc$batch_transfer_server
*copyc osc$queue_transfer_server
*copyc oss$job_paged_literal
*copyc oss$task_shared
*copyc ost$date
*copyc ost$global_task_id
*copyc ost$status
*copyc ost$system_flag
*copyc ost$user_identification
*copyc ost$caller_identifier
*copyc pmt$os_name
*copyc pmt$sense_switches
?? POP ??
*copyc pmf$job_mode
*copyc amp$return
*copyc avp$begin_account
*copyc avp$dual_state_prompt
*copyc avp$get_limit_value
*copyc avp$get_string_value
*copyc avp$ring_nominal
*copyc avp$security_option_active
*copyc avp$validate_job
*copyc bap$file_command
*copyc bap$inhibit_implicit_detach
*copyc clp$convert_integer_to_string
*copyc clp$get_processing_phase
*copyc clp$store_std_path_handle_names
*copyc clp$update_connected_files
*copyc clp$validate_local_file_name
*copyc cmp$subsystem_io_job_exit
*copyc dfp$check_job_recovery
*copyc dfp$process_job_end
*copyc dfp$send_remote_procedure_call
*copyc dpp$put_critical_message
*copyc fmp$get_system_file_id
*copyc fmp$initialize_path_table
*copyc fmp$job_exit
*copyc fsp$build_file_ref_from_elems
*copyc fsp$close_file
*copyc fsp$copy_file
*copyc fsp$create_file
*copyc fsp$open_file
*copyc i#current_sequence_position
*copyc i#move
*copyc ifp$job_initialize
*copyc ifp$purge_connection_io
*copyc iip$terminate_disconnected_job
*copyc jmf$ijle_p
*copyc jmp$add_to_server_restart_file
*copyc jmp$clone_login
*copyc jmp$delete_non_inherited_segs
*copyc jmp$determine_job_class_name
*copyc jmp$emit_communication_stat
*copyc jmp$emit_job_history_statistics
*copyc jmp$exit_job
*copyc jmp$get_server_job_end_info
*copyc jmp$initialize_job_attributes
*copyc jmp$initialize_job_local_tables
*copyc jmp$initialize_timesharing
*copyc jmp$job_is_being_leveled
*copyc jmp$print_file
*copyc jmp$save_recovery_information
*copyc jmp$save_sfid_of_swap_file
*copyc jmp$system_job
*copyc jmp$set_job_unswappable
*copyc jmp$write_recovery_info_to_disk
*copyc lgp$append_job_log_to_output
*copyc lgp$setup_access_to_local_logs
*copyc nap$parse_accounting_data
*copyc nap$process_job_termination
*copyc nap$se_synchronize
*copyc ofp$display_status_message
*copyc ofp$job_begin
*copyc ofp$job_end
*copyc ofp$screen_input_fap
*copyc ofp$screen_output_fap
*copyc osp$called_by_system_code
*copyc osp$disestablish_cond_handler
*copyc osp$enforce_exception_policies
*copyc osp$establish_block_exit_hndlr
*copyc osp$establish_condition_handler
*copyc osp$force_access_violation
*copyc osp$format_message
*copyc osp$get_status_condition_name
*copyc osp$generate_log_message
*copyc osp$generate_output_message
*copyc osp$get_job_template_name
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc osp$set_status_from_condition
*copyc osp$system_error
*copyc osp$verify_system_privilege
*copyc pfp$attach
*copyc pfp$begin_system_authority
*copyc pfp$define
*copyc pfp$define_catalog
*copyc pfp$delete_catalog_permit
*copyc pfp$end_system_authority
*copyc pfp$process_job_end
*copyc pfp$purge
*copyc pmp$continue_to_cause
*copyc pmp$convert_binary_mainframe_id
*copyc pmp$dispose_job_resource_cond
*copyc pmp$emit_job_end_statistics
*copyc pmp$exit
*copyc pmp$find_executing_task_tcb
*copyc pmp$format_compact_date
*copyc pmp$format_compact_time
*copyc pmp$get_date
*copyc pmp$get_executing_task_gtid
*copyc pmp$get_job_names
*copyc pmp$get_mainframe_id
*copyc pmp$get_pseudo_mainframe_id
*copyc pmp$get_termination_status
*copyc pmp$get_user_identification
*copyc pmp$get_unique_name
*copyc pmp$get_microsecond_clock
*copyc pmp$get_os_version
*copyc pmp$log
*copyc pmp$log_ascii
*copyc pmp$long_term_wait
*copyc pmp$manage_sense_switches
*copyc pmp$update_jmtr_tcb_target_ring
*copyc pmp$set_system_flag
*copyc qfp$discard_job
*copyc qfp$job_requests_restart
*copyc qfp$read_job_system_label
*copyc qfp$server_job_begin
*copyc qfp$set_family_unavailable
*copyc qfp$set_interactive_jrd_jad
*copyc qfp$set_job_restart
*copyc qfp$write_job_system_label
*copyc rfp$job_termination
*copyc rhp$save_link_user_description
*copyc rmp$request_null_device
*copyc rmp$request_terminal
*copyc sfp$emit_audit_statistic
*copyc sfp$emit_statistic
*copyc sfp$get_job_limit
*copyc sfp$init_job_routing_control
*copyc stp$set_end_job
*copyc syp$initialize_job_mode
*copyc tmp$disable_preemptive_commo
*copyc tmp$fetch_job_statistics

*copyc avv$account_name
*copyc avv$project_name
*copyc clv$standard_files
*copyc iiv$interactive_terminated
*copyc iiv$xt_xterm_control_block
*copyc jmv$executing_within_system_job
*copyc jmv$ijl_p
*copyc jmv$jcb
*copyc jmv$job_attributes
*copyc jmv$job_history_active
*copyc jmv$job_recovery_information_p
*copyc jmv$kjl_p
*copyc jmv$kjlx_p
*copyc jmv$known_job_list
*copyc jmv$swap_file_allocation_size
*copyc jmv$ts_job_disconnected
*copyc osv$control_codes_to_quest_mark
*copyc osv$initial_exception_context
*copyc osv$task_shared_heap
*copyc pfv$p_attached_pf_table
*copyc pfv$p_queued_catalog_table
*copyc syv$job_initialization_complete
*copyc syv$clone_enabled
*copyc syv$job_recovery_step
*copyc syv$nosve_job_template

  VAR
    jmv$login_command_logging_vers: [XREF] integer;

?? OLDTITLE ??
?? NEWTITLE := 'Global Variables Declared by this Module', EJECT ??

  VAR
    jmv$job_swap_file_id: [STATIC, oss$task_shared] amt$file_identifier,
    jmv$job_command_input_lfn: [STATIC, oss$task_shared] amt$local_file_name := osc$null_name,
    jmv$job_termination_status: [XDCL, #GATE, STATIC, oss$task_shared] ^ost$status := NIL,
    jmv$leveled_job_committed: [XDCL, #GATE, STATIC, oss$task_shared] boolean := FALSE,
    jmv$terminal_io_disabled: [XDCL, #GATE, STATIC, oss$task_shared] boolean := FALSE,
    jmv$exit_processing_inhibited: [STATIC, oss$task_shared] boolean := FALSE;

?? TITLE := '    JMP$JOB_BEGIN', EJECT ??

  PROCEDURE [XDCL, #GATE] jmp$job_begin
    (VAR users_nominal_ring: ost$ring);

    VAR
      account_name: avt$account_name,
      cloned_job: boolean,
      date: ost$date,
      get_accounting_data_p: ^nat$accounting_data_fields,
      id: ost$caller_identifier,
      ignore_status: ost$status,
      job_template_name: ost$name,
      local_status: ost$status,
      logset: pmt$ascii_logset,
      microsecond_clock_value: jmt$clock_time,
      operation_information_p: ^sft$audit_information,
      operation_status_p: ^ost$status,
      peer_accounting_information_p: ^string ( * ),
      project_name: avt$project_name,
      statistic_data: jmt$comm_acct_statistic_data,
      status: ost$status,
      system_identification_line: string (54),
      system_label_p: ^jmt$job_system_label,
      version: pmt$os_name;

    CONST
      avc$none = 'NONE                           ';

    #CALLER_ID (id);
    IF (NOT osp$called_by_system_code (id)) OR (id.ring > osc$tsrv_ring) THEN
      osp$force_access_violation;
    IFEND;

    logset := $pmt$ascii_logset [pmc$system_log, pmc$job_log];

    cloned_job := syv$job_initialization_complete;
    IF NOT cloned_job THEN

{ The job initialization capture point
{ All user specific job initialization must come AFTER this point

      jmp$initialize_job_mode;
    IFEND;

    pmp$get_date (osc$mdy_date, date, status);
    IF NOT status.normal THEN
      osp$generate_log_message (logset, status, ignore_status);
      system_identification_line (1, 8) := '        ';
    ELSE
      system_identification_line (1, 8) := date.mdy;
    IFEND;
    system_identification_line (9) := ' ';
    pmp$get_os_version (version, status);
    IF NOT status.normal THEN
      osp$generate_log_message (logset, status, ignore_status);
      system_identification_line (10, * ) := ' ';
    ELSE
      system_identification_line (10, * ) := version;
    IFEND;
    system_identification_line (34, * ) := jmv$kjl_p^ [jmv$jcb.job_id].system_job_name;

    pmp$log (system_identification_line, status);

    osp$get_job_template_name (job_template_name);
    IF job_template_name <> '' THEN
      pmp$log (job_template_name, status);
    IFEND;

    jmp_initialize_swap_file (status);
    IF NOT status.normal THEN
      osp$generate_log_message (logset, status, ignore_status);
      pmp$exit (status);
    IFEND;

    IF jmp$job_is_being_leveled () THEN
      call_server_job_begin (status);
      IF NOT status.normal THEN
        osp$generate_log_message (logset, status, ignore_status);
        pmp$exit (status);
      IFEND;
    IFEND;

    IF syv$clone_enabled AND syv$nosve_job_template THEN
      PUSH system_label_p;
      initialize_job_tables (system_label_p, status);
      IF NOT status.normal THEN
        osp$generate_log_message (logset, status, ignore_status);
        pmp$exit (status);
      IFEND;
    ELSE
      system_label_p := ^jmv$job_recovery_information_p^.job_system_label;
    IFEND;

{ NOTE: The following call "should" take place before the call to pmp$init_default_prog_options,
{       but must be done here because of a previous pfp$attach done with COMMAND as the alias.

    IF NOT jmv$kjlx_p^ [jmv$jcb.job_id].timesharing_job THEN
      clp$store_std_path_handle_names (jmv$executing_within_system_job, {first_time=} FALSE, status);
      IF NOT status.normal THEN
        osp$generate_log_message (logset, status, ignore_status);
        pmp$exit (status);
      IFEND;
    IFEND;

{ NOTE: At this point, a job is now capable of referencing itself for job attributes.
    jmp$emit_job_begin_statistics (status);
    IF NOT status.normal THEN
      osp$generate_log_message (logset, status, ignore_status);
    IFEND;

    IF jmv$job_history_active THEN
      jmp$emit_job_history_statistics (jml$job_initiated, osc$null_name, system_label_p^.system_job_name,
            jmc$blank_system_supplied_name, NIL, NIL, osc$null_name, jmc$blank_system_supplied_name,
            ignore_status);
    IFEND;

    IF system_label_p = NIL THEN
      account_name := avc$none;
      project_name := avc$none;
    ELSE
      account_name := system_label_p^.login_account;
      project_name := system_label_p^.login_project;
    IFEND;

    IF jmp$is_dual_state_job () THEN
      ifp$job_initialize (status);
      IF NOT status.normal THEN
        osp$generate_log_message (logset, status, ignore_status);
        pmp$exit (status);
      IFEND;

      jmp_initialize_job_files (status);
      IF NOT status.normal THEN
        osp$generate_log_message (logset, status, ignore_status);
        pmp$exit (status);
      IFEND;

      IF system_label_p^.optional_user_capability = avc$dual_state_prompt THEN
        avp$dual_state_prompt (system_label_p^.login_user_identification.user,
              system_label_p^.login_user_identification.family, status);
        IF NOT status.normal THEN
          osp$generate_log_message (logset, status, ignore_status);
          pmp$exit (status);
        IFEND;

        account_name := avv$account_name;
        project_name := avv$project_name;

      IFEND;

    IFEND;

    IF cloned_job THEN
      IF jmv$kjlx_p^ [jmv$jcb.job_id].timesharing_job THEN
        jmp$clone_login (status);
        IF NOT status.normal THEN
          osp$generate_log_message (logset, status, ignore_status);
          pmp$exit (status);
        IFEND;
      IFEND;
    IFEND;

    validate_job (system_label_p, account_name, project_name, users_nominal_ring, status);
    IF NOT status.normal THEN
      osp$generate_log_message (logset, status, ignore_status);
      IF system_label_p^.job_mode = jmc$interactive_connected THEN
        osp$generate_output_message (status, ignore_status);
      IFEND;
      pmp$exit (status);
    IFEND;

    clp$update_connected_files (users_nominal_ring);
    pmp$update_jmtr_tcb_target_ring (users_nominal_ring);

{ The following statistics are emitted after the call to validate_job so that
{ the account and project names will be valid.

    IF (jmv$job_attributes.originating_application_name = osc$batch_transfer_server) THEN
      statistic_data.statistic_id := jmc$ca_input_file;
      PUSH statistic_data.input_file;
      statistic_data.input_file^.job_input_device := jmv$job_attributes.job_input_device;
      statistic_data.input_file^.job_system_label_p := system_label_p;
      jmp$emit_communication_stat (statistic_data);
    ELSEIF (jmv$job_attributes.originating_application_name = osc$queue_transfer_server) THEN
      statistic_data.statistic_id := jmc$ca_dest_qf_transfer;
      PUSH statistic_data.dest_queue_file_transfer;
      statistic_data.dest_queue_file_transfer^.kind := jmc$input_file;
      statistic_data.dest_queue_file_transfer^.job_input_device := jmv$job_attributes.job_input_device;
      statistic_data.dest_queue_file_transfer^.job_system_label_p := system_label_p;
      jmp$emit_communication_stat (statistic_data);
    IFEND;

    IF (avp$security_option_active (avc$vso_security_audit) AND (system_label_p <> NIL)) THEN
      PUSH operation_information_p;
      operation_information_p^.audited_operation := sfc$ao_job_user_identification;
      operation_information_p^.user_identification.family_name_p :=
            ^system_label_p^.login_user_identification.family;
      operation_information_p^.user_identification.user_name_p :=
            ^system_label_p^.login_user_identification.user;
      operation_information_p^.user_identification.account_name_p := ^avv$account_name;
      operation_information_p^.user_identification.project_name_p := ^avv$project_name;
      IF jmv$kjlx_p^ [jmv$jcb.job_id].timesharing_job THEN

{ Get the terminal name.

        PUSH get_accounting_data_p: [1 .. 1];
        get_accounting_data_p^ [1].kind := nac$ca_device_name;
        PUSH peer_accounting_information_p: [jmv$job_attributes.job_input_device.size];
        peer_accounting_information_p^ := jmv$job_attributes.job_input_device.text;
        nap$parse_accounting_data (peer_accounting_information_p, NIL, get_accounting_data_p, local_status);
        IF local_status.normal THEN
          operation_information_p^.user_identification.terminal_name_p :=
                ^get_accounting_data_p^ [1].device_name;
        ELSE
          operation_information_p^.user_identification.terminal_name_p := NIL;
        IFEND;
      ELSE
        operation_information_p^.user_identification.terminal_name_p := NIL;
      IFEND;
      PUSH operation_status_p;
      operation_status_p^.normal := TRUE;
      sfp$emit_audit_statistic (operation_information_p^, operation_status_p^);
    IFEND;

    ofp$job_begin;

{ This request must take place after an interactive job has connected to its terminal.

    IF NOT jmp$is_xterm_job () THEN
      qfp$set_interactive_jrd_jad;
    IFEND;

{ This request should take place before returning to force the recovery information
{ out of the working set.

    jmp$write_recovery_info_to_disk;

    pmp$get_microsecond_clock (microsecond_clock_value, ignore_status);
    IF (jmv$kjlx_p^ [jmv$jcb.job_id].latest_clock_time_to_initiate < microsecond_clock_value) THEN
      osp$set_status_abnormal ('JM', jme$job_initiated_too_late, '', status);
      osp$generate_log_message (logset, status, ignore_status);
      pmp$exit (status);
    IFEND;

  PROCEND jmp$job_begin;

?? TITLE := '   JMP$JOB_BOOT', EJECT ??

  PROCEDURE [XDCL] jmp$job_boot;

    VAR
      ignore_status: ost$status,
      system_label_p: ^jmt$job_system_label,
      status: ost$status;

    fmp$initialize_path_table;

    lgp$setup_access_to_local_logs (status);
    IF NOT status.normal THEN
      pmp$exit (status);
    IFEND;

    sfp$init_job_routing_control (status);
    IF NOT status.normal THEN
      pmp$exit (status);
    IFEND;

    clp$store_std_path_handle_names (jmv$executing_within_system_job, TRUE, status);
    IF NOT status.normal THEN
      pmp$exit (status);
    IFEND;

    IF pmf$job_mode () = jmc$batch THEN
      jmp_initialize_job_files (status);
      IF NOT status.normal THEN
        pmp$exit (status);
      IFEND;
    IFEND;

    IF (NOT syv$clone_enabled) OR (NOT syv$nosve_job_template) THEN

{Job will never save a login template
{system label must be available during login for a detached job submit

      PUSH system_label_p;
      initialize_job_tables (system_label_p, status);
      IF NOT status.normal THEN
        osp$generate_log_message ($pmt$ascii_logset [pmc$system_log, pmc$job_log], status, ignore_status);
        pmp$exit (status);
      IFEND;
    IFEND;

    IF jmv$kjlx_p^ [jmv$jcb.job_id].timesharing_job THEN
      jmp$initialize_timesharing (status);
      IF NOT status.normal THEN
        osp$generate_log_message ($pmt$ascii_logset [pmc$system_log, pmc$job_log], status, ignore_status);
        pmp$exit (status);
      IFEND;
      jmp_initialize_job_files (status);
      IF NOT status.normal THEN
        osp$generate_log_message ($pmt$ascii_logset [pmc$system_log, pmc$job_log], status, ignore_status);
        pmp$exit (status);
      IFEND;
      clp$store_std_path_handle_names (jmv$executing_within_system_job, FALSE, status);
      IF NOT status.normal THEN
        osp$generate_log_message ($pmt$ascii_logset [pmc$system_log, pmc$job_log], status, ignore_status);
        pmp$exit (status);
      IFEND;
    IFEND;

  PROCEND jmp$job_boot;


?? TITLE := '    JMP$JOB_END', EJECT ??

  PROCEDURE [XDCL, #GATE] jmp$job_end;

    TYPE
      jmt$job_end_phase = (null_phase, rethread_job, append_job_log, route_output, set_job_unswappable,
            purge_command_file, purge_swap_file, disable_preemptive_commo, operator_facility_cleanup,
            cm_job_exit, delete_non_inherited_segs, ln_job_exit, rhfam_job_exit, nam_job_exit, pf_job_exit,
            set_management_cleanup, file_server_job_exit, emit_job_statistics, exit_job_request);


    VAR
      job_end_phase: [STATIC, oss$task_shared] jmt$job_end_phase := LOWERVALUE (jmt$job_end_phase),
      logset: pmt$ascii_logset,
      command_path_p: ^pft$path,
      restart_job: boolean,
      swap_path_p: ^pft$path,
      pf_cycle: pft$cycle_selector,
      password: pft$password,
      expected_status: boolean,
      files_binary_mainframe_id: pmt$binary_mainframe_id,
      file_attributes_p: ^amt$file_attributes,
      job_output_fap_p: amt$fap_pointer,
      executing_taskid: ost$global_task_id,
      ignore_status: ost$status,
      output_disposition: [STATIC, READ, oss$job_paged_literal] array [jmt$output_disposition_keys] of
            string (osc$max_name_size) := ['DISCARD_ALL_OUTPUT             ',
            'DISCARD_STANDARD_OUTPUT        ', 'LOCAL                          ',
            'PRINTER                        ', 'STANDARD_OUTPUT                ',
            'WAIT_QUEUE                     '],
      output_disposition_key: jmt$output_disposition_keys,
      reason: ost$name,
      return_files_option: pft$return_files_option,
      system_label_p: ^jmt$job_system_label,
      system_job_name: jmt$system_supplied_name,
      system_supplied_name: jmt$system_supplied_name,
      status: ost$status,
      termination_status: ost$status;

?? NEWTITLE := '    handle_block_exit', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to deal with block exit conditions that
{   arise while system_authority is in effect.

    PROCEDURE handle_block_exit
      (    condition: pmt$condition;
           condition_information_p: ^pmt$condition_information;
           sfsa_p: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        ignore_status: ost$status;

      pfp$end_system_authority;
      IF NOT status.normal THEN
        osp$set_status_from_condition (jmc$job_management_id, condition, sfsa_p, status, ignore_status);
      IFEND;
    PROCEND handle_block_exit;

?? OLDTITLE, EJECT ??

    logset := $pmt$ascii_logset [pmc$system_log];

{! Stop the music if the System Job is terminating.

    IF jmv$executing_within_system_job = TRUE THEN
      osp$system_error ('JOB_END CALLED IN SYSTEM JOB', ^status);
    IFEND;

    pmp$get_executing_task_gtid (executing_taskid);
    IF executing_taskid <> jmv$jcb.job_monitor_id THEN
      osp$set_status_abnormal ('JM', jme$job_end_called_unexpectedly, '', status);
      osp$generate_log_message (logset, status, ignore_status);
      RETURN;
    IFEND;
    output_disposition_key := jmv$kjlx_p^ [jmv$jcb.job_id].output_disposition_key;
    system_job_name := jmv$kjl_p^ [jmv$jcb.job_id].system_job_name;

    WHILE TRUE DO
      job_end_phase := SUCC (job_end_phase);
      CASE job_end_phase OF

      = rethread_job =
        jmp$set_job_term_disposition;

      = append_job_log =
        job_output_fap_p := jmp$job_file_fap (clv$standard_files [clc$sf_job_output_file].path_handle_name);
        IF (job_output_fap_p = NIL) AND (pmf$job_mode () = jmc$batch) AND
              (output_disposition_key <> jmc$discard_standard_output) AND
              (output_disposition_key <> jmc$discard_all_output) THEN
          lgp$append_job_log_to_output (status);
          IF NOT status.normal THEN
            osp$generate_log_message (logset, status, ignore_status);
          IFEND;
        IFEND;

      = route_output =
        job_output_fap_p := jmp$job_file_fap (clv$standard_files [clc$sf_job_output_file].path_handle_name);
        system_supplied_name := jmc$blank_system_supplied_name;
        IF (job_output_fap_p = NIL) AND (pmf$job_mode () = jmc$batch) AND
              (output_disposition_key <> jmc$discard_standard_output) AND
              (output_disposition_key <> jmc$discard_all_output) THEN
          dispose_of_standard_output (output_disposition_key, system_supplied_name, status);
          IF NOT status.normal THEN
            osp$generate_log_message (logset, status, ignore_status);
          IFEND;
        IFEND;

        IF jmv$job_history_active THEN
          pmp$get_termination_status (termination_status);
          reason := '';
          osp$get_status_condition_name (termination_status.condition, reason, ignore_status);

          IF (pmf$job_mode () = jmc$batch) THEN
            IF (output_disposition_key <> jmc$standard_output_path) OR (NOT status.normal) THEN

{ If the status is not normal the the copy_file has failed to dispose of standard output;  The output
{ file is then on $local.output.

              jmp$emit_job_history_statistics (jml$job_terminated,
                    output_disposition [output_disposition_key], system_job_name, system_supplied_name, NIL,
                    NIL, reason, jmc$blank_system_supplied_name, status);
            ELSE
              jmp$emit_job_history_statistics (jml$job_terminated,
                    output_disposition [output_disposition_key], system_job_name,
                    jmc$blank_system_supplied_name, NIL, NIL, reason, jmc$blank_system_supplied_name, status);
            IFEND;
          ELSE
            jmp$emit_job_history_statistics (jml$job_terminated, osc$null_name, system_job_name,
                  'TSJOB              ', NIL, NIL, reason, jmc$blank_system_supplied_name, status);
          IFEND;
          IF NOT status.normal THEN
            osp$generate_log_message (logset, status, ignore_status);
          IFEND;
        IFEND;

      = set_job_unswappable =
        jmp$set_job_unswappable (ignore_status);

      = purge_command_file =

{ Interactive jobs don't have command files and cannot be restarted.

        IF pmf$job_mode () = jmc$batch THEN
          restart_job := FALSE;

{ If the job is a batch job and the job claims that it wants to restart if it aborted we may not want to
{ delete the command file.  In order to consider this further, the job must have completed the system
{ prolog.  The job recovery step must indicate that the job has been through a recovery otherwise the
{ job abort disposition is ignored.

          IF (qfp$job_requests_restart () AND (syv$job_recovery_step <> syc$jrs_initial_step)) THEN
            pmp$get_termination_status (termination_status);

{ If the termination status of the job is not one of the expected termination statuses it is okay to
{ restart the job.  This means that the job monitor task aborted with an unexpected status and NOS/VE
{ was responsible for bringing down the user's job.

            expected_status := (termination_status.condition = jme$job_terminating_normally) OR
                  (termination_status.condition = jme$job_terminated_via_command) OR
                  (termination_status.condition = ave$bad_user_validation_info) OR
                  (termination_status.condition = jme$user_requested_exit) OR
                  (termination_status.condition = jme$login_abort_in_prolog) OR
                  (termination_status.condition = mme$job_file_tables_full) OR
                  (termination_status.condition = ife$disconnected_job_timeout);

            IF NOT expected_status THEN
              restart_job := TRUE;
              osp$generate_log_message (logset, termination_status, ignore_status);
            ELSE
              restart_job := FALSE;
            IFEND;
          IFEND;

          IF (NOT restart_job) AND jmv$kjl_p^ [jmv$jcb.job_id].login_family_available AND
                (NOT jmp$job_is_being_leveled () OR jmv$leveled_job_committed) THEN
            PUSH command_path_p: [1 .. 4];
            IF jmv$kjlx_p^ [jmv$jcb.job_id].input_file_location = jmc$ifl_login_family_queue THEN
              command_path_p^ [1] := jmv$jcb.user_id.family;
            ELSE
              command_path_p^ [1] := jmc$system_family;
            IFEND;
            command_path_p^ [2] := jmc$system_user;
            command_path_p^ [3] := jmc$job_input_catalog;
            command_path_p^ [4] (1, * ) := jmv$jcb.system_name;
            pf_cycle.cycle_option := pfc$specific_cycle;
            pf_cycle.cycle_number := 1;
            password := osc$null_name;
            osp$establish_block_exit_hndlr (^handle_block_exit);
            pfp$begin_system_authority;
            pfp$purge (command_path_p^, pf_cycle, password, status);
            pfp$end_system_authority;
            osp$disestablish_cond_handler;
            IF NOT status.normal THEN
              osp$generate_log_message (logset, status, ignore_status);
            IFEND;
          ELSEIF (NOT jmp$job_is_being_leveled () OR jmv$leveled_job_committed) THEN

{ Write an updated job label to the command file. Make it appear as though the job
{ did not initiate.  If we cannot write the updated label, the job will initiate
{ on the next deadstart or the file will be purged by recovery.  It is likely that
{ an attempt to re-start the job from this deadstart would fail since the file
{ could not be updated.

            PUSH system_label_p;
            qfp$read_job_system_label (clc$job_command_input, system_label_p^, status);
            IF status.normal THEN
              system_label_p^.job_initiation_location := '';
              qfp$write_job_system_label (clc$job_command_input, { write_label } TRUE, system_label_p^,
                    status);
              IF status.normal AND jmv$kjl_p^ [jmv$jcb.job_id].login_family_available THEN
                qfp$set_job_restart;
              ELSE
                osp$generate_log_message (logset, status, ignore_status);
              IFEND;
            ELSE
              osp$generate_log_message (logset, status, ignore_status);
            IFEND;

          ELSE { The job was leveled and failed before updating the server
            PUSH swap_path_p: [1 .. 4];
            swap_path_p^ [1] := jmc$system_family;
            swap_path_p^ [2] := jmc$system_user;
            swap_path_p^ [3] := jmc$job_swap_catalog;
            swap_path_p^ [4] (1, * ) := jmv$jcb.system_name;
            jmp$add_to_server_restart_file (swap_path_p, {recover_using_abort_disposition} FALSE);
          IFEND;
        IFEND; { job_mode = jmc$batch

      = purge_swap_file =

{ Don't need to close the swap file - bam has already done this in cleanup - whoops!

        PUSH swap_path_p: [1 .. 4];
        swap_path_p^ [1] := jmc$system_family;
        swap_path_p^ [2] := jmc$system_user;
        swap_path_p^ [3] := jmc$job_swap_catalog;
        swap_path_p^ [4] (1, * ) := jmv$jcb.system_name;
        pf_cycle.cycle_option := pfc$specific_cycle;
        pf_cycle.cycle_number := 1;
        password := osc$null_name;
        osp$establish_block_exit_hndlr (^handle_block_exit);
        pfp$begin_system_authority;
        pfp$purge (swap_path_p^, pf_cycle, password, status);
        pfp$end_system_authority;
        osp$disestablish_cond_handler;
        IF NOT status.normal THEN
          osp$generate_log_message (logset, status, ignore_status);
        IFEND;

      = disable_preemptive_commo =
        job_end_phase := PRED (disable_preemptive_commo); { inhibit phase advancement
        tmp$disable_preemptive_commo;
        job_end_phase := disable_preemptive_commo; { enable phase advancement

      = operator_facility_cleanup =
        ofp$job_end;

      = cm_job_exit =
        cmp$subsystem_io_job_exit (status);
        IF NOT status.normal THEN
          osp$generate_log_message (logset, status, ignore_status);
        IFEND;

      = delete_non_inherited_segs =

{###    jmp$delete_non_inherited_segs (status);
{###    IF NOT status.normal THEN
{###      osp$generate_log_message (logset, status, ignore_status);
{###    IFEND;

      = ln_job_exit =
        fmp$job_exit;

      = rhfam_job_exit =
        rfp$job_termination;

      = nam_job_exit =
        nap$process_job_termination;

      = pf_job_exit =
        return_files_option.return_files := FALSE;
        pmp$get_pseudo_mainframe_id (files_binary_mainframe_id);
        pfp$process_job_end (files_binary_mainframe_id, return_files_option);

      = set_management_cleanup =
        stp$set_end_job (status);
        IF NOT status.normal THEN
          osp$generate_log_message (logset, status, ignore_status);
        IFEND;

      = file_server_job_exit =

{ If the job was leveled and did not reach the commit point then don't tell the server
{ the job is completed.

        IF (NOT jmp$job_is_being_leveled () OR jmv$leveled_job_committed) THEN
          dfp$process_job_end;
        IFEND;

      = emit_job_statistics =
        pmp$emit_job_end_statistics (status);
        IF NOT status.normal THEN
          osp$generate_log_message (logset, status, ignore_status);
        IFEND;

      = exit_job_request =
        job_end_phase := PRED (exit_job_request);

{! Control is not returned to this procedure after the call to JMP$EXIT_JOB.

        jmp$exit_job;

      CASEND;
    WHILEND;

  PROCEND jmp$job_end;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$define_and_permit_catalogs', EJECT ??

  PROCEDURE [XDCL] jmp$define_and_permit_catalogs
    (VAR status: ost$status);

    VAR
      ignore_status: ost$status,
      path_p: ^pft$path;

    status.normal := TRUE;

    PUSH path_p: [1 .. 3];
    path_p^ [1] := jmc$system_family;
    path_p^ [2] := jmc$system_user;

    path_p^ [3] := jmc$job_input_catalog;
    pfp$define_catalog (path_p^, ignore_status);

    path_p^ [3] := jmc$sf_job_input_catalog;
    pfp$define_catalog (path_p^, ignore_status);

    path_p^ [3] := jmc$job_output_catalog;
    pfp$define_catalog (path_p^, ignore_status);

    path_p^ [3] := jmc$sf_job_output_catalog;
    pfp$define_catalog (path_p^, ignore_status);

    path_p^ [3] := jmc$job_swap_catalog;
    pfp$define_catalog (path_p^, ignore_status);
  PROCEND jmp$define_and_permit_catalogs;
?? OLDTITLE ??
?? NEWTITLE := 'initialize_job_tables', EJECT ??

  PROCEDURE initialize_job_tables
    (VAR system_label_p: ^jmt$job_system_label;
     VAR status: ost$status);

    VAR
      command_lfn: amt$local_file_name,
      path_p: ^pft$path,
      pf_cycle: pft$cycle_selector,
      password: pft$password,
      usage: pft$usage_selections,
      share: pft$share_selections;

?? NEWTITLE := 'handle_block_exit', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to deal with block exit conditions that
{   arise while system_authority is in effect.

    PROCEDURE handle_block_exit
      (    condition: pmt$condition;
           condition_information_p: ^pmt$condition_information;
           sfsa_p: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        ignore_status: ost$status;

      pfp$end_system_authority;
      IF NOT status.normal THEN
        osp$set_status_from_condition (jmc$job_management_id, condition, sfsa_p, status, ignore_status);
      IFEND;
    PROCEND handle_block_exit;
?? OLDTITLE, EJECT ??

    status.normal := TRUE;

    IF jmv$executing_within_system_job THEN
      system_label_p := NIL;
    ELSE

      IF jmv$kjlx_p^ [jmv$jcb.job_id].job_mode = jmc$batch THEN

{ Attach the command file for the job so we can read the system label

        PUSH path_p: [1 .. 4];
        IF jmv$kjlx_p^ [jmv$jcb.job_id].input_file_location = jmc$ifl_login_family_queue THEN
          path_p^ [1] := jmv$jcb.user_id.family;
        ELSE
          path_p^ [1] := jmc$system_family;
        IFEND;
        path_p^ [2] := jmc$system_user;
        path_p^ [3] := jmc$job_input_catalog;
        path_p^ [4] := jmv$jcb.system_name;
        pf_cycle.cycle_option := pfc$specific_cycle;
        pf_cycle.cycle_number := 1;
        password := osc$null_name;
        usage := $pft$usage_selections [pfc$read];
        share := $pft$share_selections [pfc$read];
        command_lfn := clc$job_command_input;
        osp$establish_block_exit_hndlr (^handle_block_exit);
        pfp$begin_system_authority;
        pfp$attach (command_lfn, path_p^, pf_cycle, password, usage, share, pfc$wait, status);
        pfp$end_system_authority;
        osp$disestablish_cond_handler;
        IF NOT status.normal THEN
          RETURN;
        IFEND;

{ Read the system label for the job

        qfp$read_job_system_label (command_lfn, system_label_p^, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
      ELSE
        system_label_p^ := jmv$kjlx_p^ [jmv$jcb.job_id].system_label_p^;
      IFEND;

{ Place the mainframe ID and the job initiation time in the job's system label.
{ This serves two purposes.  The first is to indicate when the job was initiated.  The second
{ is to indicate which mainframe the job initiated on.  This is necessary for
{ load-leveling.  Once the job's system label is updated on the server, the leveled
{ job is committed to execution.  Any server failure before this point must result in a
{ restart of the job.  Any server failure after this point must result in the job
{ waiting for the server.

      pmp$get_mainframe_id (system_label_p^.job_initiation_location, { ignore } status);
      system_label_p^.job_attributes.job_initiation_time := jmv$kjlx_p^ [jmv$jcb.job_id].job_initiation_time;

      IF jmv$kjlx_p^ [jmv$jcb.job_id].job_mode = jmc$batch THEN
        qfp$write_job_system_label (command_lfn, { write_label } TRUE, system_label_p^, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
      IFEND;

      jmp$save_recovery_information (system_label_p);
    IFEND; { NOT jmv$executing_in_system_job

{ Initialize the tables that are local to the job's execution environment

    jmp$initialize_job_local_tables (system_label_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    jmp$initialize_job_attributes (system_label_p, status);

  PROCEND initialize_job_tables;
?? OLDTITLE ??
?? NEWTITLE := '[INLINE] validate_job', EJECT ??

  PROCEDURE [INLINE] validate_job
    (    system_label_p: ^jmt$job_system_label;
         account_name: avt$account_name;
         project_name: avt$project_name;
     VAR users_nominal_ring: ost$ring;
     VAR status: ost$status);

    VAR
      context: ^ost$ecp_exception_context,
      job_class: jmt$job_class,
      ignore_display_format: avt$numeric_display_format,
      link_attribute_family: ost$string,
      link_attribute_user: ost$string,
      link_attribute_password: ost$string,
      link_attribute_account: ost$string,
      link_attribute_project: ost$string,
      validation_attributes: ^avt$validation_items,
      week_timeout_period: integer;

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


    IF jmv$executing_within_system_job THEN
      users_nominal_ring := osc$user_ring;
      iiv$terminal_timeout_limit := nac$max_wait_time;
      iiv$terminal_timeout_limit_left := nac$max_wait_time;

    ELSE

{ Validate the job

      PUSH validation_attributes: [1 .. 7];
      validation_attributes^ [1].key := avc$password_key;
      validation_attributes^ [1].password := system_label_p^.login_password;

      job_class := jmv$kjl_p^ [jmv$jcb.job_id].job_class;
      IF system_label_p^.perform_class_validation AND (system_label_p^.assigned_job_class <>
            osc$null_name) AND (job_class <> jmc$unassigned_job_class) THEN
        validation_attributes^ [2].key := avc$job_class_name_key;
        validation_attributes^ [2].job_class_name := system_label_p^.assigned_job_class;
      ELSE
        validation_attributes^ [2].key := avc$null_validation_key;
      IFEND;

{ Did the user specify a ring ?

      IF system_label_p^.job_execution_ring <> osc$invalid_ring THEN
        users_nominal_ring := system_label_p^.job_execution_ring;
        validation_attributes^ [3].key := avc$job_execution_ring_key;
        validation_attributes^ [3].job_execution_ring := system_label_p^.job_execution_ring;
      ELSE
        validation_attributes^ [3].key := avc$null_validation_key;
      IFEND;

      IF system_label_p^.required_user_capability <> osc$null_name THEN
        validation_attributes^ [4].key := avc$required_capability_key;
        validation_attributes^ [4].required_capability := system_label_p^.required_user_capability;
      ELSE
        validation_attributes^ [4].key := avc$null_validation_key;
      IFEND;

      validation_attributes^ [5].key := avc$job_limit_key;
      validation_attributes^ [5].limit_name := avc$cpu_time_limit_name;
      validation_attributes^ [5].user_specified := (system_label_p^.limit_information.
            cpu_time_limit_specified AND (system_label_p^.limit_information.cpu_time_limit_requested <>
            jmc$unspecified_cpu_time_limit));
      validation_attributes^ [5].job_maximum := system_label_p^.limit_information.cpu_time_limit_assigned;

      validation_attributes^ [6].key := avc$job_limit_key;
      validation_attributes^ [6].limit_name := avc$sru_limit_name;
      validation_attributes^ [6].user_specified := (system_label_p^.limit_information.
            sru_limit_specified AND (system_label_p^.limit_information.sru_limit_requested <>
            jmc$unspecified_sru_limit));
      validation_attributes^ [6].job_maximum := system_label_p^.limit_information.sru_limit_assigned;

      validation_attributes^ [7].key := avc$job_limit_key;
      validation_attributes^ [7].limit_name := avc$magnetic_tape_limit_name;
      validation_attributes^ [7].user_specified := (system_label_p^.limit_information.
            magnetic_tape_limit_specified AND (system_label_p^.limit_information.
            magnetic_tape_limit_requested <> jmc$unspecified_mag_tape_limit));
      validation_attributes^ [7].job_maximum := system_label_p^.limit_information.
            magnetic_tape_limit_assigned;

{ Validate the job.  If the validation file is on a server mainframe and the server
{ is not active, then one of two things must happen.  If the job is a leveled job,
{ the job should wait for the server mainframe to activate.  Otherwise (the job
{ is logging in thru the server) the job should abort, noting that the login
{ family is unavailable.  This will result in the job being deferred.

      REPEAT
        avp$validate_job (system_label_p^.login_user_identification.user,
              system_label_p^.login_user_identification.family, account_name, project_name,
              validation_attributes, status);
        IF (NOT status.normal) AND (status.condition = dfe$server_not_active) THEN
          IF jmp$job_is_being_leveled () THEN
            IF context = NIL THEN
              PUSH context;
              context^ := osv$initial_exception_context;
            IFEND;
            context^.condition_status := status;
            osp$enforce_exception_policies (context^);
            status := context^.condition_status;
          ELSE
            qfp$set_family_unavailable;
            RETURN;
          IFEND;
        IFEND;
      UNTIL status.normal OR (status.condition <> dfe$server_not_active) OR ((context <> NIL) AND
            (NOT context^.wait));
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      IF NOT jmp$is_xterm_job () THEN
        avp$get_limit_value (avc$terminal_timeout_limit, avc$user, iiv$terminal_timeout_limit,
              ignore_display_format, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        IF iiv$terminal_timeout_limit < (nac$max_wait_time DIV 60000) THEN
          iiv$terminal_timeout_limit := iiv$terminal_timeout_limit * 60000 - 30000;
        ELSE
          iiv$terminal_timeout_limit := nac$max_wait_time;
        IFEND;
      ELSE
{ Because an xterm job does not yet support attach_job, the job
{ cannot be disconnected for terminal timeout.

        iiv$terminal_timeout_limit := nac$max_wait_time;
      IFEND;
      iiv$terminal_timeout_limit_left := iiv$terminal_timeout_limit;

{ Save info for the memory link.  This will be modified latter with the valid account and project names if
{ system accounting is active and the users validation is project required.


      avp$get_string_value (avc$link_attribute_family, avc$user, link_attribute_family, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      avp$get_string_value (avc$link_attribute_user, avc$user, link_attribute_user, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      avp$get_string_value (avc$link_attribute_password, avc$user, link_attribute_password, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      avp$get_string_value (avc$link_attribute_charge, avc$user, link_attribute_account, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      avp$get_string_value (avc$link_attribute_project, avc$user, link_attribute_project, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      rhp$save_link_user_description (link_attribute_user.value (1, 31), link_attribute_family.value (1, 31),
            link_attribute_password.value (1, 31), link_attribute_account.value (1, 31),
            link_attribute_project.value (1, 31), status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      IF system_label_p^.job_execution_ring = osc$invalid_ring THEN
        users_nominal_ring := avp$ring_nominal ();
      IFEND;
    IFEND;

  PROCEND validate_job;
?? OLDTITLE ??
?? NEWTITLE := 'dispose_of_standard_output', EJECT ??

  PROCEDURE dispose_of_standard_output
    (VAR output_disposition_key: jmt$output_disposition_keys;
     VAR system_supplied_name: jmt$system_supplied_name;
     VAR status: ost$status);

    VAR
      boi_attributes_p: ^amt$file_attributes,
      ignore_status: ost$status,
      logset: pmt$ascii_logset,
      mandated_creation_attributes_p: ^fst$file_cycle_attributes,
      nominal_ring: ost$ring,
      print_output: boolean;

?? NEWTITLE := 'handle_out_of_space', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to deal with the out of space condition.

    PROCEDURE handle_out_of_space
      (    condition: pmt$condition;
           condition_information_p: ^pmt$condition_information;
           sfsa_p: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        ignore_status: ost$status;

      IF (condition.selector = pmc$user_defined_condition) AND
            (condition.user_condition_name = osc$space_unavailable_condition) THEN
        osp$set_status_condition (jme$no_space_for_file, status);
        jmp$update_display_message (status);

{ This is called twice to fish out any signals and flags that are waiting to be processed.
{ This forces the job to wait for 5 minutes unless another event triggers the task to come ready.

        pmp$long_term_wait (100, 100);
        pmp$long_term_wait (300000, 300000);
        ofp$display_status_message (' ', ignore_status);
        status.normal := TRUE;
        RETURN;
      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
      IFEND;
    PROCEND handle_out_of_space;
?? OLDTITLE ??
?? EJECT ??
    logset := $pmt$ascii_logset [pmc$system_log];

    PUSH boi_attributes_p: [1 .. 1];
    boi_attributes_p^ [1].key := amc$open_position;
    boi_attributes_p^ [1].open_position := amc$open_at_boi;
    IF status.normal THEN
      bap$file_command (clc$job_output, boi_attributes_p, status);
    IFEND;
    IF NOT status.normal THEN
      osp$generate_log_message (logset, status, ignore_status);
      RETURN;
    IFEND;

{ Did the user specify a file for standard output?

    print_output := (output_disposition_key <> jmc$standard_output_path);
    IF NOT print_output THEN

    /copy_standard_output/
      BEGIN
        nominal_ring := avp$ring_nominal ();
        PUSH mandated_creation_attributes_p: [1 .. 1];
        mandated_creation_attributes_p^ [1].selector := fsc$ring_attributes;
        mandated_creation_attributes_p^ [1].ring_attributes.r1 := nominal_ring;
        mandated_creation_attributes_p^ [1].ring_attributes.r2 := nominal_ring;
        mandated_creation_attributes_p^ [1].ring_attributes.r3 := nominal_ring;


        osp$establish_condition_handler (^handle_out_of_space, {block_exit} FALSE);
        fsp$copy_file (clc$job_output, jmv$job_attributes.output_disposition_path, NIL, NIL,
              mandated_creation_attributes_p, status);
        IF NOT status.normal THEN
          osp$disestablish_cond_handler;
          amp$return (jmv$job_attributes.output_disposition_path, ignore_status);
          osp$generate_log_message (logset, status, ignore_status);
          EXIT /copy_standard_output/;
        IFEND;
        osp$disestablish_cond_handler;

      END /copy_standard_output/;
    IFEND;

    IF NOT status.normal THEN

{ The copy did not work for some reason.  So print the file.

      status.normal := TRUE;
      print_output := TRUE;
    IFEND;

    IF print_output THEN
      jmp$print_file (':$LOCAL.OUTPUT.$BOI', NIL, system_supplied_name, status);

    /wait_for_resources/
      WHILE NOT status.normal DO
        IF (status.condition = jme$maximum_output) OR (status.condition = jme$no_space_for_file) THEN
          jmp$update_display_message (status);

{ This is called twice to fish out any signals and flags that are waiting to
{ be processed.  This forces the job to wait for 5 minutes unless another
{ event triggers the task to come ready.

          pmp$long_term_wait (100, 100);
          pmp$long_term_wait (300000, 300000);
          ofp$display_status_message (' ', ignore_status);
          output_disposition_key := jmv$kjlx_p^ [jmv$jcb.job_id].output_disposition_key;
          IF (output_disposition_key = jmc$discard_standard_output) OR
                (output_disposition_key = jmc$discard_all_output) THEN
            RETURN;
          IFEND;
          jmp$print_file (':$LOCAL.OUTPUT.$BOI', NIL, system_supplied_name, status);
        ELSE
          osp$generate_log_message (logset, status, ignore_status);
          EXIT /wait_for_resources/;
        IFEND;
      WHILEND /wait_for_resources/;
    IFEND;

  PROCEND dispose_of_standard_output;


?? TITLE := '    INITIALIZE_JOB_FILES', EJECT ??

  PROCEDURE jmp_initialize_job_files
    (VAR status: ost$status);

    VAR
      null_attribute: [STATIC, READ, oss$job_paged_literal] array
            [1 .. 1] of ift$connection_attribute := [[ifc$null_connection_attribute]];


    status.normal := TRUE;

    IF pmf$job_mode () <> jmc$batch THEN

      rmp$request_terminal (clc$job_command_input, NIL, null_attribute, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      rmp$request_terminal (clc$job_input, NIL, null_attribute, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      rmp$request_terminal (clc$job_output, NIL, null_attribute, status);

    ELSEIF jmv$executing_within_system_job THEN
      rmp$request_null_device (clc$job_command_input, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      rmp$request_null_device (clc$job_input, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      rmp$request_null_device (clc$job_output, status);

    ELSE

{ For batch jobs, the command file is already attached at this point

      jmv$job_command_input_lfn := clc$job_command_input;
      rmp$request_null_device (clc$job_input, status);
    IFEND;

  PROCEND jmp_initialize_job_files;

?? TITLE := '    INITIALIZE_SWAP_FILE', EJECT ??

  PROCEDURE jmp_initialize_swap_file
    (VAR status: ost$status);

    VAR
      attachment_options_p: ^fst$attachment_options,
      device_attributes: array [1 .. 2] of fst$device_attribute,
      mandated_creation_options_p: ^fst$file_cycle_attributes,
      path_length: integer,
      path_p: ^pft$path,
      resolved_path: fst$path,
      retention: pft$retention,
      sfid: gft$system_file_identifier,
      swap_file_fid: amt$file_identifier,
      swap_file_path: string (fsc$max_path_size),
      swap_file_user_information: jmt$swap_file_user_info;

?? NEWTITLE := '    handle_block_exit', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to deal with block exit conditions that
{   arise while system_authority is in effect.

    PROCEDURE handle_block_exit
      (    condition: pmt$condition;
           condition_information_p: ^pmt$condition_information;
           sfsa_p: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        ignore_status: ost$status;

      pfp$end_system_authority;
      IF NOT status.normal THEN
        osp$set_status_from_condition (jmc$job_management_id, condition, sfsa_p, status, ignore_status);
      IFEND;
    PROCEND handle_block_exit;

?? OLDTITLE, EJECT ??

    PUSH path_p: [1 .. 4];

    IF NOT jmv$executing_within_system_job THEN
      device_attributes [1].selector := fsc$allocation_size;
      device_attributes [1].allocation_size := jmv$swap_file_allocation_size;
      device_attributes [2].selector := fsc$mass_storage_class;
      device_attributes [2].mass_storage_class := dmc$swap_file_class;

{ Currently, the swap file version isn't used for anything but just in case it
{ is necessary to distinguish swap files in the future it might come in handy.

      swap_file_user_information.version := jmc$swap_file_version_1;
      swap_file_user_information.server_mainframe_id := jmv$known_job_list.server_data.
            state_data [jmv$kjl_p^ [jmv$jcb.job_id].server_index].mainframe_id;
      path_p^ [1] := jmc$system_family;
      path_p^ [2] := jmc$system_user;
      path_p^ [3] := jmc$job_swap_catalog;
      path_p^ [4] (1, * ) := jmv$jcb.system_name;
      fsp$build_file_ref_from_elems (path_p, swap_file_path, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      osp$establish_block_exit_hndlr (^handle_block_exit);
      pfp$begin_system_authority;

      fsp$create_file (swap_file_path, {attachment options} NIL, {cycle attributes} NIL, ^device_attributes,
            {file attributes} NIL, resolved_path, status);

      pfp$end_system_authority;
      osp$disestablish_cond_handler;
      IF NOT status.normal THEN {status from fsp$create_file
        RETURN;
      IFEND;

      PUSH attachment_options_p: [1 .. 2];
      attachment_options_p^ [1].selector := fsc$access_and_share_modes;
      attachment_options_p^ [1].access_modes.selector := fsc$specific_access_modes;
      attachment_options_p^ [1].access_modes.value := $fst$file_access_options
            [fsc$read, fsc$shorten, fsc$append, fsc$modify];
      attachment_options_p^ [1].share_modes.selector := fsc$specific_share_modes;
      attachment_options_p^ [1].share_modes.value := $fst$file_access_options [];
      attachment_options_p^ [2].selector := fsc$open_share_modes;
      attachment_options_p^ [2].open_share_modes := $fst$file_access_options [];

      PUSH mandated_creation_options_p: [1 .. 2];
      mandated_creation_options_p^ [1].selector := fsc$ring_attributes;
      mandated_creation_options_p^ [1].ring_attributes.r1 := osc$tsrv_ring;
      mandated_creation_options_p^ [1].ring_attributes.r2 := osc$tsrv_ring;
      mandated_creation_options_p^ [1].ring_attributes.r3 := osc$tsrv_ring;
      mandated_creation_options_p^ [2].selector := fsc$user_information;
      i#move (^swap_file_user_information, ^mandated_creation_options_p^ [2].
            user_information, #SIZE (jmt$swap_file_user_info));

      fsp$open_file (swap_file_path, amc$record, attachment_options_p, NIL, mandated_creation_options_p, NIL,
            NIL, swap_file_fid, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

{ Call bap$inhibit_implicit_detach so that the swap file is not detached by bap$loaded_ring_cleanup.

      bap$inhibit_implicit_detach (swap_file_fid);

      fmp$get_system_file_id (swap_file_path, sfid, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      jmp$save_sfid_of_swap_file (sfid, status);
    IFEND;

  PROCEND jmp_initialize_swap_file;

?? TITLE := '[XDCL] jmp$set_job_term_disposition', EJECT ??

  PROCEDURE [XDCL] jmp$set_job_term_disposition;

    qfp$discard_job;
  PROCEND jmp$set_job_term_disposition;


?? TITLE := '    JMP$GET_JOB_COMMAND_INPUT_LFN', EJECT ??

  PROCEDURE [XDCL] jmp$get_job_command_input_lfn
    (VAR local_file_name: amt$local_file_name);

    local_file_name := jmv$job_command_input_lfn;

  PROCEND jmp$get_job_command_input_lfn;


?? TITLE := '   JMP$OPERATOR_JOB', EJECT ??

  FUNCTION [XDCL, #GATE] jmp$operator_job: boolean;

{--------------------------------------------------------------------
{                       WARNING!!!
{ This function will be eliminated in the near future.
{   Use jmp$system_job or a capability-based validation instead.
{---------------------------------------------------------------------

    jmp$operator_job := jmv$executing_within_system_job;
  FUNCEND jmp$operator_job;

?? TITLE := '    JMP$JOB_FILE_FAP', EJECT ??

  FUNCTION [XDCL, #GATE] jmp$job_file_fap
    (    local_file_name: amt$local_file_name): amt$fap_pointer;

    IF jmp$system_job () THEN
      IF (local_file_name = clv$standard_files [clc$sf_command_file].path_handle_name) OR
            (local_file_name = clv$standard_files [clc$sf_job_input_file].path_handle_name) THEN
        jmp$job_file_fap := ^ofp$screen_input_fap;
      ELSEIF (local_file_name = clv$standard_files [clc$sf_job_output_file].path_handle_name) OR
            (local_file_name = clv$standard_files [clc$sf_display_a_file].path_handle_name) OR
            (local_file_name = clv$standard_files [clc$sf_display_b_file].path_handle_name) THEN
        jmp$job_file_fap := ^ofp$screen_output_fap;
      ELSE
        jmp$job_file_fap := NIL;
      IFEND;
    ELSE
      jmp$job_file_fap := NIL;
    IFEND;
  FUNCEND jmp$job_file_fap;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$terminate_job_flag_handler', EJECT ??
*copy jmh$terminate_job_flag_handler

  PROCEDURE [XDCL] jmp$terminate_job_flag_handler
    (    flag_id: ost$system_flag);

    VAR
      executing_taskid: ost$global_task_id,
      ignore_status: ost$status,
      termination_status: ost$status;

    IF jmv$executing_within_system_job = TRUE THEN
      RETURN;
    IFEND;

    pmp$get_executing_task_gtid (executing_taskid);
    IF executing_taskid <> jmv$jcb.job_monitor_id THEN
      RETURN;
    IFEND;

{ The messages logged by this routine are not message templates because the job's environment
{ may be so messed up that translating a message template is not possible.  This is particularly
{ possible for jobs that need to be killed.

    IF NOT jmv$exit_processing_inhibited THEN
      IF jmp$is_dual_state_job () THEN
        iip$terminate_disconnected_job;
      IFEND;

      jmv$exit_processing_inhibited := TRUE;
      pmp$log ('Job terminated via a TERMINATE_JOB command (exit).', ignore_status);
      osp$set_status_abnormal ('JM', jme$job_terminated_via_command, '', termination_status);
      jmp$set_job_termination_status (termination_status);
      pmp$exit (termination_status);

    ELSEIF (NOT jmv$terminal_io_disabled) AND (pmf$job_mode () <> jmc$batch) THEN
      pmp$log ('Job terminated via a TERMINATE_JOB command (disable).', ignore_status);
      IF (jmp$is_dual_state_job () OR jmp$is_xterm_job () OR
            (jmv$job_attributes.originating_application_name = osc$timesharing)) THEN
        disable_terminal_io;
      IFEND;
    ELSE
      IF flag_id = jmc$kill_job_flag THEN
        pmp$log_ascii ('Job terminated via a TERMINATE_JOB command (kill).', $pmt$ascii_logset
              [pmc$system_log, pmc$job_log], pmc$msg_origin_system, ignore_status);
        pmp$set_system_flag (pmc$kill_task_flag, executing_taskid, ignore_status);
      ELSE
        pmp$log ('Job terminated via a TERMINATE_JOB command (ignore).', ignore_status);
      IFEND;
    IFEND;

  PROCEND jmp$terminate_job_flag_handler;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$handle_logout_flag', EJECT ??

  PROCEDURE [XDCL] jmp$handle_logout_flag
    (    flag_id: ost$system_flag);

    VAR
      termination_status: ost$status;

    IF NOT jmv$exit_processing_inhibited THEN
      jmv$exit_processing_inhibited := TRUE;
      osp$set_status_abnormal ('JM', jme$job_terminating_normally, '', termination_status);
      jmp$set_job_termination_status (termination_status);
      pmp$exit (termination_status);
    IFEND;

  PROCEND jmp$handle_logout_flag;


?? TITLE := '    JMP$HANDLE_JOB_RESOURCE_SIGNAL', EJECT ??

  PROCEDURE [XDCL] jmp$handle_job_resource_signal
    (    originator: ost$global_task_id;
         signal: pmt$signal);

    VAR
      job_resource_signal: jmt$job_resource_signal;

    job_resource_signal.signal := signal;

    pmp$dispose_job_resource_cond (job_resource_signal.signal_contents);

  PROCEND jmp$handle_job_resource_signal;


?? TITLE := '    JMP$HANDLE_SIGNAL_SENSE_SWITCH', EJECT ??

  PROCEDURE [XDCL] jmp$handle_signal_sense_switch
    (    originator: ost$global_task_id;
         signal: pmt$signal);

    VAR
      signal_contents_p: ^jmt$sense_switch_signal,
      results: pmt$sense_switches,
      status: ost$status;

    status.normal := TRUE;

    signal_contents_p := #LOC (signal.contents);
    pmp$manage_sense_switches (signal_contents_p^. ON, signal_contents_p^. OFF, results, status);

  PROCEND jmp$handle_signal_sense_switch;


?? TITLE := '    DISABLE_TERMINAL_IO', EJECT ??

  PROCEDURE disable_terminal_io;

    VAR
      data1: ^char,
      data: ^SEQ ( * ),
      ignore_status: ost$status,
      local_status: ost$status,
      logset: pmt$ascii_logset,
      terminal_file_id: amt$file_identifier;

    logset := $pmt$ascii_logset [pmc$system_log, pmc$job_log];
    local_status.normal := TRUE;

    jmv$terminal_io_disabled := TRUE;

    IF jmp$is_dual_state_job () THEN
      ifp$purge_connection_io (local_status);
      IF NOT local_status.normal THEN
        osp$generate_log_message (logset, local_status, ignore_status);
      IFEND;

    ELSEIF (jmv$job_attributes.originating_application_name = osc$timesharing) THEN
      fsp$open_file (osc$timesharing_terminal_file, amc$record, NIL, NIL, NIL, NIL, NIL, terminal_file_id,
            local_status);
      IF local_status.normal THEN
        PUSH data: [[REP 1 OF char]];
        RESET data;
        NEXT data1 IN data;
        data1^ := ' ';
        nap$se_synchronize (terminal_file_id, nac$se_synchronize_all_data, data^, local_status);
        IF local_status.normal THEN
          fsp$close_file (terminal_file_id, local_status);
        ELSE
          fsp$close_file (terminal_file_id, ignore_status);
        IFEND;
      IFEND;
      IF NOT local_status.normal THEN
        osp$generate_log_message (logset, local_status, ignore_status);
      IFEND;
    IFEND;
  PROCEND disable_terminal_io;
?? OLDTITLE ??
?? NEWTITLE := 'call_server_job_begin', EJECT ??

{ PURPOSE:
{   The purpose of this request is to notify a job's server mainframe that the
{ job has been initiated on a client mainframe.  This request will result in
{ the state of the job changing from queued to initiated in the server's KJL.
{ The job's job system label on the server is updated to reflect that the
{ job has been initiated on the client.
{ This procedure is called by the job on the client mainframe.

  PROCEDURE call_server_job_begin
    (VAR status: ost$status);

?? NEWTITLE := 'dfp$remote_procedure_call_ch', EJECT ??

{ PURPOSE:
{   This procedure is a condition handler established to call a routine to clear the assignment of a task
{   services queue_entry if a task aborts with a queue_entry assigned to it.  The queue_entry must be clear
{   before the task can safely exit.

    PROCEDURE dfp$remote_procedure_call_ch
      (    condition: pmt$condition;
           cond_desc: ^pmt$condition_information;
           save: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      dfp$ch_cleanup;
      osp$set_status_from_condition (dfc$file_server_id, condition, save, status, handler_status);
      EXIT call_server_job_begin;

    PROCEND dfp$remote_procedure_call_ch;
*block
*copyc dfp$begin_ch_remote_proc_call
*copyc dfp$end_ch_remote_proc_call
*blockend
?? OLDTITLE, EJECT ??
    VAR
      data_size: dft$send_data_size,
      ignore_recovery_occured: boolean,
      ignore_status: ost$status,
      job_begin_information: jmt$jl_server_job_end_info,
      local_job_begin_information_p: ^jmt$jl_server_job_end_info,
      local_job_terminated_p: ^boolean,
      queue_entry_location: dft$rpc_queue_entry_location,
      parameter_size: dft$send_parameter_size,
      receive_from_server_data_p: dft$p_receive_data,
      receive_from_server_params_p: dft$p_receive_parameters,
      send_to_server_data_p: dft$p_send_data,
      send_to_server_parameters_p: dft$p_send_parameters,
      server_location: dft$server_location;

    status.normal := TRUE;

{ Need to convert the server's mainframe id to a queue entry location.

    jmp$get_server_job_end_info (job_begin_information);
    server_location.server_location_selector := dfc$mainframe_id;
    pmp$convert_binary_mainframe_id (job_begin_information.server_mainframe_id,
          server_location.server_mainframe, { ignore } status);

    dfp$begin_ch_remote_proc_call (server_location, { allowed_when_server_deactivated } FALSE,
          queue_entry_location, send_to_server_parameters_p, send_to_server_data_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Build the send to server parameters and data to send to the server mainframe.
{ RPC sequences are already reset.

    NEXT local_job_begin_information_p IN send_to_server_parameters_p;
    local_job_begin_information_p^ := job_begin_information;

    parameter_size := i#current_sequence_position (send_to_server_parameters_p);
    data_size := i#current_sequence_position (send_to_server_data_p);

    dfp$send_remote_procedure_call (queue_entry_location, dfc$rpc_jl_job_begin, parameter_size, data_size,
          receive_from_server_params_p, receive_from_server_data_p, status);
    IF status.normal THEN

{ Once the job's system label is updated on the server, the leveled
{ job is committed to execution.  Any server failure before this point must result in a
{ restart of the job.  Any server failure after this point must result in the job
{ waiting for the server.

      jmv$leveled_job_committed := TRUE;
      NEXT local_job_terminated_p IN receive_from_server_params_p;
      IF local_job_terminated_p^ THEN
        pmp$set_system_flag (jmc$terminate_job_flag, jmv$jcb.job_monitor_id, ignore_status);
      IFEND;
      dfp$end_ch_remote_proc_call (queue_entry_location, status);
    ELSE
      dfp$end_ch_remote_proc_call (queue_entry_location, ignore_status);
    IFEND;
  PROCEND call_server_job_begin;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$server_job_begin', EJECT ??
*copy jmh$server_job_begin

  PROCEDURE [XDCL] jmp$server_job_begin
    (VAR received_from_client_params_p { Input } : dft$p_receive_parameters;
     VAR received_from_client_data_p { Input } : dft$p_receive_data;
     VAR send_to_client_params_p { Output } : dft$p_send_parameters;
     VAR send_to_client_data_p { Output } : dft$p_send_data;
     VAR parameter_size: dft$send_parameter_size;
     VAR data_size: dft$send_data_size;
     VAR status: ost$status);

    VAR
      command_lfn: amt$local_file_name,
      ignore_status: ost$status,
      job_begin_information_p: ^jmt$jl_server_job_end_info,
      job_terminated_p: ^boolean,
      path_p: ^pft$path,
      pf_cycle: pft$cycle_selector,
      password: pft$password,
      share: pft$share_selections,
      system_label_p: ^jmt$job_system_label,
      usage: pft$usage_selections;

?? NEWTITLE := 'handle_block_exit', EJECT ??

{ PURPOSE:
{   The purpose of this procedure is to deal with block exit conditions that
{   arise while system_authority is in effect.

    PROCEDURE handle_block_exit
      (    condition: pmt$condition;
           condition_information_p: ^pmt$condition_information;
           sfsa_p: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        ignore_status: ost$status;

      pfp$end_system_authority;
      IF NOT status.normal THEN
        osp$set_status_from_condition (jmc$job_management_id, condition, sfsa_p, status, ignore_status);
      IFEND;
    PROCEND handle_block_exit;
?? OLDTITLE, EJECT ??

    status.normal := TRUE;

{ RPC sequences are already reset.

    NEXT job_begin_information_p IN received_from_client_params_p;
    NEXT job_terminated_p IN send_to_client_params_p;
    PUSH system_label_p;
    PUSH path_p: [1 .. 4];
    path_p^ [2] := jmc$system_user;
    path_p^ [3] := jmc$job_input_catalog;
    path_p^ [4] := job_begin_information_p^.system_job_name;
    qfp$server_job_begin (job_begin_information_p^, job_terminated_p^, path_p^ [1]);

    parameter_size := i#current_sequence_position (send_to_client_params_p);
    data_size := i#current_sequence_position (send_to_client_data_p);

    pf_cycle.cycle_option := pfc$specific_cycle;
    pf_cycle.cycle_number := 1;
    password := osc$null_name;
    usage := $pft$usage_selections [pfc$read];
    share := $pft$share_selections [pfc$read];
    pmp$get_unique_name (command_lfn, ignore_status);
    osp$establish_block_exit_hndlr (^handle_block_exit);
    pfp$begin_system_authority;
    pfp$attach (command_lfn, path_p^, pf_cycle, password, usage, share, pfc$no_wait, status);
    pfp$end_system_authority;
    osp$disestablish_cond_handler;
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Read the system label for the job

    qfp$read_job_system_label (command_lfn, system_label_p^, status);
    IF NOT status.normal THEN
      amp$return (command_lfn, ignore_status);
      RETURN;
    IFEND;

{ Place the mainframe ID of the client mainframe in the job's system label.
{ This serves two purposes.  The first is to indicate when the job was initiated.  The second
{ is to indicate which mainframe the job initiated on.  This is necessary for
{ load-leveling.

    pmp$convert_binary_mainframe_id (job_begin_information_p^.client_mainframe_id,
          system_label_p^.job_initiation_location, { ignore } status);
    qfp$write_job_system_label (command_lfn, { write_label } TRUE, system_label_p^, status);
    IF NOT status.normal THEN
      amp$return (command_lfn, ignore_status);
      RETURN;
    IFEND;

    amp$return (command_lfn, status);
  PROCEND jmp$server_job_begin;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$enable_terminal_io', EJECT ??

  PROCEDURE [XDCL, #GATE] jmp$enable_terminal_io;

    jmv$terminal_io_disabled := FALSE;

  PROCEND jmp$enable_terminal_io;

?? TITLE := '    [XDCL, #GATE] JMP$ENABLE_EXIT_PROCESSING', EJECT ??

  PROCEDURE [XDCL, #GATE] jmp$enable_exit_processing;

    jmv$exit_processing_inhibited := FALSE;

  PROCEND jmp$enable_exit_processing;

?? TITLE := '    [XDCL, #GATE] JMP$INHIBIT_EXIT_PROCESSING', EJECT ??

  PROCEDURE [XDCL, #GATE] jmp$inhibit_exit_processing;

    jmv$exit_processing_inhibited := TRUE;

  PROCEND jmp$inhibit_exit_processing;

?? TITLE := '    JMP$LOGOUT', EJECT ??

  PROCEDURE [XDCL, #GATE] jmp$logout
    (VAR status: ost$status);

    VAR
      termination_status: ost$status,
      executing_taskid: ost$global_task_id;

    status.normal := TRUE;

    IF jmv$executing_within_system_job THEN
      osp$set_status_abnormal ('JM', jme$illegal_system_job_command, '"LOGOUT"', status);
      RETURN;
    IFEND;

    pmp$get_executing_task_gtid (executing_taskid);

    IF executing_taskid <> jmv$jcb.job_monitor_id THEN
      pmp$set_system_flag (jmc$logout_flag_id, jmv$jcb.job_monitor_id, status);
      IF NOT status.normal THEN
        osp$system_error ('SEND LOGOUT FLAG FAILURE', ^status);
      IFEND;
      pmp$exit (status);

{ exit keypoint for logout is task end keypoint in syp$return_jobs_r1_resources

    ELSE
      IF NOT jmv$exit_processing_inhibited THEN
        jmv$exit_processing_inhibited := TRUE;
        osp$set_status_abnormal ('JM', jme$job_terminating_normally, '', termination_status);
        jmp$set_job_termination_status (termination_status);
        pmp$exit (termination_status);

{ exit keypoint for logout is task end keypoint in syp$return_jobs_r1_resources

      IFEND;
    IFEND;

  PROCEND jmp$logout;

?? TITLE := '    JMP$SET_JOB_TERMINATION_STATUS', EJECT ??

{
{ PURPOSE:
{   Sets the status to be returned by the SCL function $JOB_TERMINATION_STATUS.
{

  PROCEDURE [XDCL, #GATE, INLINE] jmp$set_job_termination_status
    (    status: ost$status);

    IF jmv$job_termination_status = NIL THEN
      ALLOCATE jmv$job_termination_status IN osv$task_shared_heap^;
      jmv$job_termination_status^ := status;
    IFEND;

  PROCEND jmp$set_job_termination_status;

?? TITLE := '    JMP$EMIT_JOB_BEGIN_STATISTICS', EJECT ??

  PROCEDURE jmp$emit_job_begin_statistics
    (VAR status: ost$status);

    VAR
      user_id: ost$user_identification,
      user_job_name: jmt$user_supplied_name,
      system_job_name: jmt$system_supplied_name,
      job_mode: jmt$job_mode,
      mode_data: string (11);

    pmp$get_user_identification (user_id, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    sfp$emit_statistic (jml$user_id, user_id.user, NIL, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pmp$get_job_names (user_job_name, system_job_name, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    sfp$emit_statistic (jml$user_job_name, user_job_name, NIL, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    job_mode := pmf$job_mode ();
    IF job_mode = jmc$batch THEN
      mode_data (1, 11) := 'BATCH      ';
    ELSEIF (job_mode = jmc$interactive_connected) OR (job_mode = jmc$interactive_cmnd_disconnect) OR
          (job_mode = jmc$interactive_line_disconnect) OR (job_mode = jmc$interactive_sys_disconnect) THEN
      mode_data (1, 11) := 'INTERACTIVE';
    ELSE
      mode_data (1, 11) := '           ';
    IFEND;

    sfp$emit_statistic (jml$job_mode, mode_data, NIL, status);

  PROCEND jmp$emit_job_begin_statistics;

?? TITLE := 'JMP$LOG_STATUS_ERROR', EJECT ??

  PROCEDURE [XDCL] jmp$log_status_error
    (    status_to_display: ost$status;
         logset: pmt$ascii_logset;
     VAR status: ost$status);

    VAR
      line_count: 1 .. osc$max_status_message_lines,
      status_message_p: ^ost$status_message,
      status_message_line_count_p: ^ost$status_message_line_count,
      status_message_line_size_p: ^ost$status_message_line_size,
      status_message_line_p: ^ost$status_message_line,
      status_message: ost$status_message;

    status.normal := TRUE;
    osp$format_message (status_to_display, osc$full_message_level, osc$max_status_message_line,
          status_message, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    status_message_p := ^status_message;
    RESET status_message_p;
    NEXT status_message_line_count_p IN status_message_p;
    FOR line_count := 1 TO status_message_line_count_p^ DO
      NEXT status_message_line_size_p IN status_message_p;
      NEXT status_message_line_p: [status_message_line_size_p^] IN status_message_p;
      pmp$log_ascii (status_message_line_p^, logset, pmc$msg_origin_system, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    FOREND;

  PROCEND jmp$log_status_error;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$update_display_message', EJECT ??
*copy jmh$update_display_message

{ DESIGN:
{   If the status condition is jme$no_space_for_file, notify the operator.

  PROCEDURE [XDCL, #GATE] jmp$update_display_message
    (    message_status: ost$status);

    VAR
      formatted_message: ost$status_message,
      formatted_message_line_count_p: ^ost$status_message_line_count,
      formatted_message_line_p: ^ost$status_message_line,
      formatted_message_line_size_p: ^ost$status_message_line_size,
      formatted_message_p: ^ost$status_message,
      local_status: ost$status;

    osp$verify_system_privilege;

    formatted_message_p := ^formatted_message;
    osp$format_message (message_status, osc$brief_message_level, jmc$display_message_size, formatted_message,
          local_status);
    IF local_status.normal THEN

{ The line count should always be one.  The message template cannot exceed a
{ total of jmc$display_message_size characters in length.  If this length is
{ exceeded, the message is truncated.

      NEXT formatted_message_line_count_p IN formatted_message_p;
      NEXT formatted_message_line_size_p IN formatted_message_p;
      NEXT formatted_message_line_p: [formatted_message_line_size_p^] IN formatted_message_p;
      ofp$display_status_message (formatted_message_line_p^, { ignore } local_status);

{ If necessary, notify the operator.

      IF message_status.condition = jme$no_space_for_file THEN
        dpp$put_critical_message (formatted_message_line_p^, {ignore} local_status);
      IFEND;
    IFEND;
  PROCEND jmp$update_display_message;
?? OLDTITLE ??
?? NEWTITLE := 'jmp$initialize_job_mode', EJECT ??

  PROCEDURE jmp$initialize_job_mode;

    IF (NOT syv$clone_enabled) OR jmv$executing_within_system_job OR (NOT syv$nosve_job_template) THEN
      syp$initialize_job_mode; {Just sets syv$job_initialization_complete}
      RETURN;
    IFEND;

    IF (pfv$p_attached_pf_table.table_p <> NIL) OR (pfv$p_queued_catalog_table <> NIL) THEN
      osp$system_error (' Cannot initialize job mode', NIL);
      RETURN;
    IFEND;

    syp$initialize_job_mode;

  PROCEND jmp$initialize_job_mode;

  FUNCTION [XDCL, #GATE] jmp$job_initialized: boolean;

    jmp$job_initialized := syv$job_initialization_complete;

  FUNCEND jmp$job_initialized;

?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$is_dual_state_job', EJECT ??

  FUNCTION [XDCL, #GATE] jmp$is_dual_state_job: boolean;

    jmp$is_dual_state_job := (jmv$job_attributes.originating_application_name = osc$dual_state_interactive);

  FUNCEND jmp$is_dual_state_job;

?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$is_xterm_job', EJECT ??
 FUNCTION [XDCL, #GATE] jmp$is_xterm_job: boolean;

    jmp$is_xterm_job := jmv$xterm_job;

  FUNCEND jmp$is_xterm_job;

?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$is_xterm_task', EJECT ??
 FUNCTION [XDCL, #GATE] jmp$is_xterm_task
   (task_id: pmt$task_id): boolean;

    IF iiv$xt_xterm_control_block.task.exists THEN
      jmp$is_xterm_task := (iiv$xt_xterm_control_block.task.id = task_id);
    ELSE
      jmp$is_xterm_task := FALSE;
    IFEND;

  FUNCEND jmp$is_xterm_task;

?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$timesharing', EJECT ??

  FUNCTION [XDCL, #GATE] jmp$timesharing: boolean;

    jmp$timesharing := jmv$kjlx_p^ [jmv$jcb.job_id].timesharing_job;

  FUNCEND jmp$timesharing;


?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$log_edited_login_command', EJECT ??
*copy jmh$log_edited_login_command

  PROCEDURE [XDCL] jmp$log_edited_login_command
    (VAR status: ost$status);

    CONST
      line_size_maximum = 2000;

    CONST
      c$none = 'NONE';

    VAR
      ascii_logset: pmt$ascii_logset,
      ijl_entry_p: ^jmt$initiated_job_list_entry,
      line: string (line_size_maximum),
      line_size: 0 .. line_size_maximum,
      job_abort_dispositions: [STATIC, READ, oss$job_paged_literal] array [jmt$job_abort_disposition] of
            string (9) := ['RESTART', 'TERMINATE'],
      job_recovery_dispositions: [STATIC, READ, oss$job_paged_literal] array [jmt$job_recovery_disposition] of
            string (9) := ['CONTINUE', 'RESTART', 'TERMINATE'],
      job_class_name: jmt$job_class_name,
      job_qualifier_exists: boolean,
      job_qualifier_index: 1 .. jmc$maximum_job_qualifiers,
      tcb_p: ^pmt$task_control_block,
      user_information: jmt$user_information;

?? NEWTITLE := 'add_date_time_value', EJECT ??

    PROCEDURE add_date_time_value
      (    date_time_value: jmt$date_time);

      VAR
        date: ost$date,
        ignore_status: ost$status,
        time: ost$time;

      IF date_time_value.specified THEN
        pmp$format_compact_date (date_time_value.date_time, osc$iso_date, date, ignore_status);
        pmp$format_compact_time (date_time_value.date_time, osc$hms_time, time, ignore_status);
        add_to_line (date.iso);
        add_to_line ('.');
        add_to_line (time.hms);
      ELSE
        add_to_line ('NONE');
      IFEND;
    PROCEND add_date_time_value;
?? OLDTITLE ??
?? NEWTITLE := '[INLINE] add_integer_value', EJECT ??

    PROCEDURE [INLINE] add_integer_value
      (    integer_value: integer);

      VAR
        ignore_status: ost$status,
        integer_string_value: ost$string;

      clp$convert_integer_to_string (integer_value, 10, FALSE, integer_string_value, ignore_status);
      add_to_line (integer_string_value.value (1, integer_string_value.size));
    PROCEND add_integer_value;
?? OLDTITLE ??
?? NEWTITLE := 'add_limit_value', EJECT ??

    PROCEDURE add_limit_value
      (    parameter_name: string ( * <= 34);
           limit_name: ost$name;
           display_unlimited_value: boolean);

      VAR
        ignore_status: ost$status,
        limit_value: sft$limit;

      sfp$get_job_limit (limit_name, limit_value, ignore_status);

      IF (display_unlimited_value = FALSE)
{   } AND (limit_value.job_abort_limit = sfc$unlimited) OR
{       } ((avc$magnetic_tape_limit_name = limit_name) AND (limit_value.job_abort_limit = 101)) THEN

{       So far, I could not figure out, where the 101 as the default value for avc$magnetic_tape_limit_name
{       comes from .... ADMV shows a value of unlimited!

        RETURN;

      ELSE
        add_to_line (parameter_name);
        IF limit_value.job_abort_limit = sfc$unlimited THEN
          add_to_line ('UNLIMITED');
        ELSE
          add_integer_value (limit_value.job_abort_limit);
        IFEND;
      IFEND;

    PROCEND add_limit_value;
?? OLDTITLE ??
?? NEWTITLE := '[INLINE] add_to_line', EJECT ??

    PROCEDURE [INLINE] add_to_line
      (    text: string ( * ));

      line (line_size + 1, STRLENGTH (text)) := text;
      line_size := line_size + STRLENGTH (text);
      WHILE (line_size > 0) AND (line (line_size) = ' ') DO
        line_size := line_size - 1;
      WHILEND;

    PROCEND add_to_line;
?? OLDTITLE ??

    status.normal := TRUE;
    jmp$determine_job_class_name (jmv$kjl_p^ [jmv$jcb.job_id].job_class, job_class_name, { ignore } status);

    avp$begin_account (jmv$jcb.user_id.family, jmv$jcb.user_id.user, avv$account_name, avv$project_name,
          jmv$jcb.jobname, jmv$kjl_p^ [jmv$jcb.job_id].job_class, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    ijl_entry_p := jmf$ijle_p (jmv$kjl_p^ [jmv$jcb.job_id].initiated_job_list_ordinal);
    line_size := 0;

    CASE jmv$login_command_logging_vers OF
    = 1 =
{ Abbreaviated parameters, UJN as 2. parameter
      add_to_line ('LOGIN, LU=');
      add_to_line (jmv$jcb.user_id.user);
      add_to_line (', UJN=');
      add_to_line (jmv$jcb.jobname);
      add_to_line (', LF=');
      add_to_line (jmv$jcb.user_id.family);
      add_to_line (', LA=');
      IF avv$account_name = osc$null_name THEN
        add_to_line ('NONE');
      ELSE
        add_to_line (avv$account_name);
      IFEND;
      add_to_line (', LP=');
      IF avv$project_name = osc$null_name THEN
        add_to_line ('NONE');
      ELSE
        add_to_line (avv$project_name);
      IFEND;
      add_limit_value (', CTL=', avc$cpu_time_limit_name, TRUE);
      add_to_line (', ERT=');
      add_date_time_value (jmv$job_attributes.earliest_run_time);
      add_to_line (', JAD=');
      add_to_line (job_abort_dispositions [ijl_entry_p^.queue_file_information.job_abort_disposition]);
      add_to_line (', JC=');
      add_to_line (job_class_name);
      add_to_line (', JDBU=NO, JER=');
      pmp$find_executing_task_tcb (tcb_p);
      add_integer_value (tcb_p^.target_ring);
      add_to_line (', JQ=(');
      job_qualifier_exists := FALSE;
      FOR job_qualifier_index := 1 TO jmc$maximum_job_qualifiers DO
        IF jmv$job_attributes.job_qualifier_list [job_qualifier_index] <> osc$null_name THEN
          job_qualifier_exists := TRUE;
          add_to_line (jmv$job_attributes.job_qualifier_list [job_qualifier_index]);
          add_to_line (',');
        IFEND;
      FOREND;
      IF job_qualifier_exists THEN
        line (line_size) := ')';
      ELSE
        add_to_line ('NONE)');
      IFEND;
      add_to_line (', JRD=');
      add_to_line (job_recovery_dispositions [ijl_entry_p^.queue_file_information.job_recovery_disposition]);
      add_to_line (', LRT=');
      add_date_time_value (jmv$job_attributes.latest_run_time);
      add_limit_value (', MTL=', avc$magnetic_tape_limit_name, TRUE);
      add_to_line (', MAXWS=');
      IF jmv$jcb.max_working_set_size = jmc$unlimited_working_set_size THEN
        add_to_line ('UNLIMITED');
      ELSE
        add_integer_value (jmv$jcb.max_working_set_size);
      IFEND;
      add_limit_value (', SL=', avc$sru_limit_name, TRUE);
      add_to_line (', UI=''');
      #TRANSLATE (osv$control_codes_to_quest_mark, jmv$job_attributes.user_information, user_information);
      add_to_line (user_information);
      add_to_line ('''');

    = 2 =
{ Abbreaviated parameters, UJN as 2. parameter, ignore NONE/UNLIMITED
{ parameters
      add_to_line ('LOGIN, LU=');
      add_to_line (jmv$jcb.user_id.user);
      add_to_line (', UJN=');
      add_to_line (jmv$jcb.jobname);
      add_to_line (', LF=');
      add_to_line (jmv$jcb.user_id.family);
      IF (avv$account_name <> osc$null_name) AND (avv$account_name <> c$none) THEN
        add_to_line (', LA=');
        add_to_line (avv$account_name);
      IFEND;
      IF (avv$project_name <> osc$null_name) AND (avv$project_name <> c$none) THEN
        add_to_line (', LP=');
        add_to_line (avv$project_name);
      IFEND;
      add_limit_value (', CTL=', avc$cpu_time_limit_name, FALSE);
      IF jmv$job_attributes.earliest_run_time.specified THEN
        add_to_line (', ERT=');
        add_date_time_value (jmv$job_attributes.earliest_run_time);
      IFEND;
      add_to_line (', JAD=');
      add_to_line (job_abort_dispositions [ijl_entry_p^.queue_file_information.job_abort_disposition]);
      add_to_line (', JC=');
      add_to_line (job_class_name);

      pmp$find_executing_task_tcb (tcb_p);
      IF tcb_p^.target_ring <> osc$user_ring THEN
        add_to_line (', JER=');
        add_integer_value (tcb_p^.target_ring);
      IFEND;

      job_qualifier_exists := FALSE;

    /scan_job_qualifiers/
      FOR job_qualifier_index := 1 TO jmc$maximum_job_qualifiers DO
        IF jmv$job_attributes.job_qualifier_list [job_qualifier_index] <> osc$null_name THEN
          job_qualifier_exists := TRUE;
          EXIT /scan_job_qualifiers/; {----->
        IFEND;
      FOREND /scan_job_qualifiers/;
      IF job_qualifier_exists THEN
        add_to_line (', JQ=(');
        FOR job_qualifier_index := 1 TO jmc$maximum_job_qualifiers DO
          IF jmv$job_attributes.job_qualifier_list [job_qualifier_index] <> osc$null_name THEN
            add_to_line (jmv$job_attributes.job_qualifier_list [job_qualifier_index]);
            add_to_line (',');
          IFEND;
        FOREND;
        line (line_size) := ')';
      IFEND;
      add_to_line (', JRD=');
      add_to_line (job_recovery_dispositions [ijl_entry_p^.queue_file_information.job_recovery_disposition]);
      IF jmv$job_attributes.latest_run_time.specified THEN
        add_to_line (', LRT=');
        add_date_time_value (jmv$job_attributes.latest_run_time);
      IFEND;
      add_limit_value (', MTL=', avc$magnetic_tape_limit_name, FALSE);
      IF jmv$jcb.max_working_set_size <> jmc$unlimited_working_set_size THEN
        add_to_line (', MAXWS=');
        add_integer_value (jmv$jcb.max_working_set_size);
      IFEND;
      add_limit_value (', SL=', avc$sru_limit_name, FALSE);
      IF jmv$job_attributes.user_information <> '' THEN
        add_to_line (', UI=''');
        #TRANSLATE (osv$control_codes_to_quest_mark, jmv$job_attributes.user_information, user_information);
        add_to_line (user_information);
        add_to_line ('''');
      IFEND;

    ELSE {original version, jmv$login_command_logging_vers = 0
      add_to_line ('LOGIN, LOGIN_USER=');
      add_to_line (jmv$jcb.user_id.user);
      add_to_line (', LOGIN_FAMILY=');
      add_to_line (jmv$jcb.user_id.family);
      add_to_line (', LOGIN_ACCOUNT=');
      IF avv$account_name = osc$null_name THEN
        add_to_line ('NONE');
      ELSE
        add_to_line (avv$account_name);
      IFEND;
      add_to_line (', LOGIN_PROJECT=');
      IF avv$project_name = osc$null_name THEN
        add_to_line ('NONE');
      ELSE
        add_to_line (avv$project_name);
      IFEND;
      add_limit_value (', CPU_TIME_LIMIT=', avc$cpu_time_limit_name, TRUE);
      add_to_line (', EARLIEST_RUN_TIME=');
      add_date_time_value (jmv$job_attributes.earliest_run_time);
      add_to_line (', JOB_ABORT_DISPOSITION=');
      add_to_line (job_abort_dispositions [ijl_entry_p^.queue_file_information.job_abort_disposition]);
      add_to_line (', JOB_CLASS=');
      add_to_line (job_class_name);
      add_to_line (', JOB_DEFERRED_BY_USER=NO, JOB_EXECUTION_RING=');
      pmp$find_executing_task_tcb (tcb_p);
      add_integer_value (tcb_p^.target_ring);
      add_to_line (', JOB_QUALIFIER=(');
      job_qualifier_exists := FALSE;
      FOR job_qualifier_index := 1 TO jmc$maximum_job_qualifiers DO
        IF jmv$job_attributes.job_qualifier_list [job_qualifier_index] <> osc$null_name THEN
          job_qualifier_exists := TRUE;
          add_to_line (jmv$job_attributes.job_qualifier_list [job_qualifier_index]);
          add_to_line (',');
        IFEND;
      FOREND;
      IF job_qualifier_exists THEN
        line (line_size) := ')';
      ELSE
        add_to_line ('NONE)');
      IFEND;
      add_to_line (', JOB_RECOVERY_DISPOSITION=');
      add_to_line (job_recovery_dispositions [ijl_entry_p^.queue_file_information.job_recovery_disposition]);
      add_to_line (', LATEST_RUN_TIME=');
      add_date_time_value (jmv$job_attributes.latest_run_time);
      add_limit_value (', MAGNETIC_TAPE_LIMIT=', avc$magnetic_tape_limit_name, TRUE);
      add_to_line (', MAXIMUM_WORKING_SET=');
      IF jmv$jcb.max_working_set_size = jmc$unlimited_working_set_size THEN
        add_to_line ('UNLIMITED');
      ELSE
        add_integer_value (jmv$jcb.max_working_set_size);
      IFEND;
      add_limit_value (', SRU_LIMIT=', avc$sru_limit_name, TRUE);
      add_to_line (', USER_INFORMATION=''');
      #TRANSLATE (osv$control_codes_to_quest_mark, jmv$job_attributes.user_information, user_information);
      add_to_line (user_information);
      add_to_line (''', USER_JOB_NAME=');
      add_to_line (jmv$jcb.jobname);
    CASEND;

    ?IF clc$compiling_for_test_harness THEN
      ascii_logset := $pmt$ascii_logset [pmc$job_log];
    ?ELSE
      ascii_logset := $pmt$ascii_logset [pmc$job_log, pmc$system_log];
    ?IFEND;

    pmp$log_ascii (line (1, line_size), ascii_logset, pmc$msg_origin_command, status);
    ?IF clc$compiling_for_test_harness THEN
      RETURN; {----->
    ?ELSE
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;
    ?IFEND;

    ofp$display_status_message (line (1, ofc$max_display_message), status);
  PROCEND jmp$log_edited_login_command;
?? OLDTITLE ??
MODEND jmm$job_monitor;
