?? NEWTITLE := 'NOS/VE : File Management : Cycle Manager' ??
MODULE fmm$cycle_manager;
?? RIGHT := 110 ??

{  PURPOSE:  This deck contains procedures which access and manipulate
{            information related to cycles.

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cyc$max_string_size
*copyc fmc$current_revision_level
*copyc fmc$entry_assigned
*copyc fmc$test_jr_constants
*copyc fmc$unique_label_id
*copyc fsc$local
*copyc jmc$system_family
*copyc rmc$maximum_density
*copyc ame$attribute_validation_errors
*copyc ame$lfn_program_actions
*copyc ame$put_validation_errors
*copyc ame$ring_validation_errors
*copyc cle$ecc_file_reference
*copyc dme$tape_errors
*copyc fme$file_management_errors
*copyc fse$attach_validation_errors
*copyc fse$system_conditions
*copyc pfe$error_condition_codes
*copyc rme$request_command_exceptions
*copyc rme$request_mass_storage
*copyc amt$file_byte_address
*copyc amt$local_file_name
*copyc amt$ring_attributes
*copyc bat$block_header
*copyc bat$global_file_information
*copyc bat$instance_attributes
*copyc bat$tape_descriptor
*copyc dmt$chapter_number
*copyc fmt$cd_attachment_options
*copyc fmt$cycle_formerly_opened_info
*copyc fmt$file_attribute_keys
*copyc fmt$mass_storage_request_info
*copyc fmt$open_cleanup_work_list
*copyc fmt$path_description_unit
*copyc fmt$path_handle
*copyc fmt$path_table_cycle_info
*copyc fmt$pf_attachment_info
*copyc fmt$removable_media_req_info
*copyc fmt$static_label_header
*copyc fst$detachment_options
*copyc fst$mass_storage_device_info
*copyc fst$path_handle_name
*copyc fst$transfer_size
*copyc gft$file_kind
*copyc ift$connection_attributes
*copyc jmt$system_label_info_length
*copyc ost$caller_identifier
*copyc ost$status
*copyc rmt$allocation_size
*copyc rmt$device_class
*copyc rmt$mass_storage_class
*copyc rmt$recorded_vsn
*copyc rmt$tape_reservation
?? POP ??
*copyc fmf$ring_attributes_valid
*copyc amp$return
*copyc avp$get_capability
*copyc avp$system_administrator
*copyc bap$fetch_tape_validation
*copyc bap$set_evaluated_file_abnormal
*copyc bap$validate_compatibility
*copyc clp$construct_path_handle_name
*copyc clp$convert_file_ref_to_string
*copyc clp$return_connected_file
*copyc clp$validate_local_file_name
*copyc cmp$class_in_volume
*copyc dmp$close_tape_volume
*copyc dmp$create_file_entry
*copyc dmp$destroy_file
*copyc dmp$get_tape_volume_information
*copyc dmp$get_tape_volume_list
*copyc dmp$replace_tape_vsn_list
*copyc dmp$set_file_limit
*copyc fmp$catalog_set_file_attributes
*copyc fmp$create_cycle_description
*copyc fmp$delete_path_description
*copyc fmp$evaluate_path
*copyc fmp$expand_file_label
*copyc fmp$get_cycle_description
*copyc fmp$get_path_string
*copyc fmp$is_file_attached
*copyc fmp$locate_cd_via_path_handle
*copyc fmp$lock_path_table
*copyc fmp$process_pt_request
*copyc fmp$put_label_attributes
*copyc fmp$unlock_path_table
*copyc fmp$verify_attribute_limits
*copyc fsp$path_element
*copyc fsp$set_evaluated_file_abnormal
*copyc ifp$invoke_pause_utility
*copyc iop$create_rvl_entry
*copyc iop$delete_rvl_entries_via_ssn
*copyc iop$delete_rvl_entry
*copyc jmp$is_xterm_job
*copyc jmp$system_job
*copyc mmp$get_segment_length
*copyc mmp$open_file_segment
*copyc nap$se_return_file
*copyc nlp$cancel_switch_offer
*copyc osp$append_status_file
*copyc osp$append_status_parameter
*copyc osp$decrement_locked_variable
*copyc osp$disestablish_cond_handler
*copyc osp$enforce_exception_policies
*copyc osp$establish_block_exit_hndlr
*copyc osp$establish_condition_handler
*copyc osp$fetch_locked_variable
*copyc osp$file_access_condition
*copyc osp$generate_log_message
*copyc osp$generate_unique_binary_name
*copyc osp$set_locked_variable
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc osp$set_status_from_condition
*copyc osp$system_error
*copyc pfp$begin_system_authority
*copyc pfp$check_device_availability
*copyc pfp$end_system_authority
*copyc pfp$return_permanent_file
*copyc pfp$save_file_label
*copyc pmp$continue_to_cause
*copyc pmp$get_job_names
*copyc pmp$get_user_identification
*copyc pmp$wait
*copyc rfp$delete_connection
*copyc rmp$clear_explicit_reserve
*copyc sfp$get_job_limit
*copyc syp$hang_if_job_jrt_set
*copyc syp$pop_inhibit_job_recovery
*copyc syp$push_inhibit_job_recovery
*copyc amv$aam_file_organizations
*copyc amv$device_class_names
*copyc fmv$default_detachment_options
*copyc fmv$global_file_information
*copyc fmv$initial_cdu_pointer
*copyc fmv$static_label_header
*copyc fmv$system_file_attributes
*copyc fmv$tape_attachment_information
*copyc fmv$tape_descriptor
*copyc gfv$null_sfid
*copyc jmv$executing_within_system_job
*copyc mmv$max_segment_length
*copyc mmv$preset_conversion_table
*copyc osv$initial_exception_context
*copyc osv$job_pageable_heap
*copyc osv$task_private_heap
*copyc osv$task_shared_heap
*copyc rmv$null_device_set
*copyc rmv$requested_volume_attributes
*copyc sfv$dynamic_file_space_limits
*copyc fmi$put_job_routing_label
*copyc i#build_adaptable_seq_pointer
*copyc i#current_sequence_position
*copyc i#move
?? TITLE := 'Global Declarations Declared by This Module', EJECT ??

  CONST
    one_second = 1000 {milliseconds} ;

  CONST
    dm_file_class_index = 1,
    dm_clear_space_index = 3,
    dm_file_limit_index = 4,
    dm_volume_overflow_index = 7,
    dm_owner = 8,
    dm_preset_value_index = 9,
    dm_allocation_size_index = 10,
    dm_initial_volume_index = 11,
    dm_transfer_size_index = 12;

  VAR
    dm_file_attributes: [STATIC, READ, oss$job_paged_literal] array
          [dm_file_class_index .. dm_transfer_size_index] of dmt$new_file_attribute := [
          {   } [dmc$class, rmc$msc_user_temporary_files],
          {   } [dmc$class_ordinal, dmc$default_class_ordinal],
          {   } [dmc$clear_space, FALSE],
          {   } [dmc$file_limit, amc$file_byte_limit],
          {   } [dmc$locked_file, [FALSE]],
          {   } [dmc$master_volume_required, FALSE],
          {   } [dmc$overflow, TRUE],
          {   } [dmc$owner, sfc$temp_file_space_limit],
          {   } [dmc$preset_value, 0],
          {   } [dmc$requested_allocation_size, dmc$unspecified_allocation_size],
          {   } [dmc$requested_volume, [rmc$unspecified_vsn, osc$null_name]],
          {   } [dmc$requested_transfer_size, dmc$unspecified_transfer_size]];

  CONST
    mm_ring_numbers_index = 1,
    mm_access_control_index = 2,
    mm_software_attributes_index = 3,
    mm_transfer_size_index = 4;

  VAR
    execute_access: [STATIC, READ, oss$job_paged_literal] pft$usage_selections := [pfc$execute],
    null_set: [STATIC, READ, oss$job_paged_literal] pft$usage_selections := [],
    read_access: [STATIC, READ, oss$job_paged_literal] pft$usage_selections := [pfc$read],
    write_access: [STATIC, READ, oss$job_paged_literal] pft$usage_selections :=
          [pfc$append, pfc$modify, pfc$shorten];

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$attach_file', EJECT ??
*copy fmh$attach_file

  PROCEDURE [XDCL, #GATE] fmp$attach_file
    (    local_file_name: amt$local_file_name;
         global_file_name: ost$binary_unique_name;
         internal_cycle_name: ost$binary_unique_name;
         sfid: gft$system_file_identifier;
         usage_mode: pft$usage_selections;
         share_mode: pft$share_selections;
         validation_ring: ost$valid_ring;
         file_space_limit_kind: sft$file_space_limit_kind;
         p_file_label: fmt$p_file_label;
         p_pf_attachment_info: ^fmt$pf_attachment_info;
         device_class: rmt$device_class;
         p_removable_media_req_info: {input} ^fmt$removable_media_req_info;
         p_volume_list: {input} ^rmt$volume_list;
     VAR evaluated_file_reference: {i/o} fst$evaluated_file_reference;
     VAR status: ost$status);

    CONST
      checksum_present = TRUE,
      expand_label = TRUE;

    VAR
      cycle_description: ^fmt$cycle_description,
      cycle_formerly_opened_info: fmt$cycle_formerly_opened_info,
      expanded_label: bat$static_label_attributes,
      fs_path: fst$path,
      fs_path_size: fst$path_size,
      ignore_process_pt_results: bat$process_pt_results,
      job_label: ^SEQ ( * ),
      job_label_size: jmt$system_label_info_length,
      last_path_element: ^fst$path_element_string,
      p_file_label_header: ^fmt$static_label_header,
      process_pt_work_list: bat$process_pt_work_list,
      ring_attributes: amt$ring_attributes,
      ring_attributes_source: amt$attribute_source,
      static_label_header: ^fmt$static_label_header,
      tape_descriptor: ^bat$tape_descriptor,
      tape_validation: boolean;

?? NEWTITLE := '  attach_file_handler', EJECT ??

    PROCEDURE attach_file_handler
      (    condition: pmt$condition;
           p_condition_info: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR condition_status: ost$status);

      VAR
        ignore_status: ost$status;

      CASE condition.selector OF
      = ifc$interactive_condition =
        CASE condition.interactive_condition OF
        = ifc$pause_break, ifc$job_reconnect =
          ifp$invoke_pause_utility (ignore_status);
        = ifc$terminate_break =
          pmp$continue_to_cause (pmc$execute_standard_procedure, condition_status);
          osp$set_status_from_condition (rmc$resource_management_id, condition, save_area, status,
                ignore_status);
          EXIT fmp$attach_file; {----->
        ELSE
          pmp$continue_to_cause (pmc$execute_standard_procedure, condition_status);
        CASEND;
      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, condition_status);
      CASEND;

    PROCEND attach_file_handler;
?? OLDTITLE ??
?? EJECT ??
    status.normal := TRUE;

    IF p_file_label <> NIL THEN
      fmp$expand_file_label (p_file_label, expand_label, job_label, job_label_size,
            cycle_formerly_opened_info.ring_attributes, cycle_formerly_opened_info.ring_attributes_source,
            cycle_formerly_opened_info.cycle_previously_opened, expanded_label, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;

      IF NOT fmf$ring_attributes_valid (cycle_formerly_opened_info, usage_mode, validation_ring) THEN
        osp$set_status_abnormal (amc$access_method_id, ame$ring_validation_error, '', status);
        RETURN; {----->
      IFEND;
    IFEND;

    process_pt_work_list := $bat$process_pt_work_list [bac$record_path, bac$resolve_path,
          bac$return_cycle_description, bac$create_cycle_description, bac$inhibit_locking_pt];
    fmp$process_pt_request (process_pt_work_list, local_file_name, evaluated_file_reference,
          cycle_description, ignore_process_pt_results, status);
    IF NOT status.normal THEN
      RETURN; {----->
    ELSEIF cycle_description = NIL THEN
      osp$set_status_abnormal (amc$access_method_id, fme$no_cycle_description, '', status);
      RETURN; {----->
    IFEND;

    verify_device_assignment (evaluated_file_reference, device_class, cycle_description, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    assign_device_class (device_class, cycle_description);
    cycle_description^.system_file_id := sfid;

    IF fsp$path_element (^evaluated_file_reference, 1) ^ <> fsc$local THEN
      cycle_description^.system_file_label.descriptive_label.permanent_file := TRUE;
      cycle_description^.system_file_label.descriptive_label.application_info :=
            p_pf_attachment_info^.application_info;
      cycle_description^.system_file_label.descriptive_label.global_share_mode := share_mode;
      cycle_description^.system_file_label.descriptive_label.global_access_mode := usage_mode;
      cycle_description^.system_file_label.descriptive_label.global_file_name := global_file_name;
      cycle_description^.system_file_label.descriptive_label.internal_cycle_name := internal_cycle_name;
      cycle_description^.file_space_limit_kind := file_space_limit_kind;
      cycle_description^.permanent_file := TRUE;
      cycle_description^.apfid := p_pf_attachment_info^.apfid;
      #UNCHECKED_CONVERSION (usage_mode, cycle_description^.attached_access_modes);
      #UNCHECKED_CONVERSION (share_mode, cycle_description^.attached_share_modes);
      cycle_description^.global_file_information^.implicit_detach_inhibited := FALSE;
      IF p_pf_attachment_info^.implicit_attach AND (NOT jmv$executing_within_system_job) THEN
        last_path_element := fsp$path_element (^evaluated_file_reference,
              evaluated_file_reference.number_of_path_elements);
        IF (fsp$path_element (^evaluated_file_reference, 1) ^ = '$SYSTEM') AND ((last_path_element^ =
              'BOUND_PRODUCT') OR (last_path_element^ = 'TERMINAL_DEFINITIONS')) AND
              (usage_mode = $pft$usage_selections [pfc$read, pfc$execute]) AND
              (share_mode = $pft$usage_selections [pfc$read, pfc$execute]) THEN
          cycle_description^.global_file_information^.implicit_detach_inhibited := TRUE;
        IFEND;
      IFEND;
      cycle_description^.password_protected := p_pf_attachment_info^.password_protected;
      cycle_description^.system_file_label_catalogued := FALSE;
      IF p_file_label <> NIL THEN
        cycle_description^.system_file_label.file_previously_opened :=
              cycle_formerly_opened_info.cycle_previously_opened;
        put_label_in_cd (p_file_label, cycle_description, evaluated_file_reference.path_handle_info.
              path_handle, status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
        IF job_label_size <> 0 THEN
          fmi$put_job_routing_label (job_label_size, job_label, cycle_description, status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;
        IFEND;
        cycle_description^.system_file_label_catalogued := TRUE;
      IFEND;
    IFEND;

    IF device_class = rmc$magnetic_tape_device THEN
      cycle_description^.global_file_information^.device_dependent_info.device_class :=
            rmc$magnetic_tape_device;
      IF fsp$path_element (^evaluated_file_reference, 1) ^ = fsc$local THEN
        cycle_description^.system_file_label.descriptive_label.global_share_mode := share_mode;
        cycle_description^.system_file_label.descriptive_label.global_access_mode := usage_mode;
        #UNCHECKED_CONVERSION (usage_mode, cycle_description^.attached_access_modes);
        #UNCHECKED_CONVERSION (share_mode, cycle_description^.attached_share_modes);
      IFEND;
      ALLOCATE cycle_description^.global_file_information^.device_dependent_info.tape_descriptor:
            [[REP (#SIZE (bat$tape_descriptor)) OF cell]] IN osv$task_shared_heap^;
      RESET cycle_description^.global_file_information^.device_dependent_info.tape_descriptor;
      NEXT tape_descriptor IN cycle_description^.global_file_information^.device_dependent_info.
            tape_descriptor;
      tape_descriptor^ := fmv$tape_descriptor;
      tape_descriptor^.requested_density := p_removable_media_req_info^.density;
      tape_descriptor^.tape_attachment_information := fmv$tape_attachment_information;
      tape_descriptor^.tape_label_attr_command_info := fmv$tape_attachment_information;

      IF status.normal THEN
        REPEAT
          iop$create_rvl_entry (sfid, p_removable_media_req_info^.density, global_file_name,
                evaluated_file_reference.path_handle_info.path_handle, rmv$requested_volume_attributes,
                p_volume_list^, p_removable_media_req_info^.write_ring, status);
          IF NOT status.normal AND (status.condition = dme$unable_to_lock_tape_table) THEN
            pmp$wait (one_second, one_second);
          IFEND;
        UNTIL status.normal OR (status.condition <> dme$unable_to_lock_tape_table);
        IF status.normal THEN
          cycle_description^.system_file_label.descriptive_label.internal_cycle_name :=
                cycle_description^.system_file_label.descriptive_label.global_file_name;
        IFEND;
      IFEND;
    IFEND;

  PROCEND fmp$attach_file;

?? TITLE := 'PROCEDURE [XDCL] fmp$catalog_system_file_label', EJECT ??

  PROCEDURE [XDCL] fmp$catalog_system_file_label
    (    system_file_label: ^fmt$system_file_label;
         job_routing_label: ^SEQ ( * );
         job_routing_label_length: jmt$system_label_info_length;
         apfid: pft$attached_permanent_file_id;
         required_permission: pft$permit_options;
     VAR status: ost$status);

    VAR
      i: integer,
      label_header: ^fmt$static_label_header,
      label_pointer: ^SEQ ( * ),
      label_size: integer,
      rest_of_static_label: ^SEQ ( * ),
      route_info: ^SEQ ( * ),
      static_label_header: ^fmt$static_label_header,
      static_label_size: integer;

    status.normal := TRUE;

    IF system_file_label^.static_label = NIL THEN
      label_size := #SIZE (fmt$static_label_header) + job_routing_label_length;
      PUSH label_pointer: [[REP label_size OF cell]];

      RESET label_pointer;
      NEXT label_header IN label_pointer;
      label_header^ := fmv$static_label_header;
      label_header^.job_routing_label_size := job_routing_label_length;
      label_header^.file_previously_opened := system_file_label^.file_previously_opened;
    ELSE { system_file_label^.static_label <> NIL }
      static_label_size := #SIZE (system_file_label^.static_label^);
      label_size := static_label_size + job_routing_label_length;
      PUSH label_pointer: [[REP label_size OF cell]];

      RESET label_pointer;
      RESET system_file_label^.static_label;
      i#move (system_file_label^.static_label, label_pointer, static_label_size);
      NEXT label_header IN label_pointer;
      label_header^.file_previously_opened := system_file_label^.file_previously_opened;
      label_header^.job_routing_label_size := job_routing_label_length;

      IF (job_routing_label_length <> 0) AND (static_label_size > #SIZE (fmt$static_label_header)) THEN

{ There is more of the static label to NEXT over, to get to the end.

        label_size := label_size - (#SIZE (fmt$static_label_header) + job_routing_label_length);
        NEXT rest_of_static_label: [[REP label_size OF cell]] IN label_pointer;
      IFEND;
    IFEND;

    IF job_routing_label <> NIL THEN
      NEXT route_info: [[REP job_routing_label_length OF cell]] IN label_pointer;
      route_info^ := job_routing_label^;
    IFEND;

    pfp$save_file_label (apfid, label_pointer, required_permission, status);
  PROCEND fmp$catalog_system_file_label;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$cleanup_open', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$cleanup_open
    (    path_handle: fmt$path_handle;
     VAR work_list: {i/o} fmt$open_cleanup_work_list);

    VAR
      cycle_description: ^fmt$cycle_description,
      error: boolean,
      open_count: integer,
      ignore_status: ost$status;

    fmp$locate_cd_via_path_handle (path_handle, TRUE {lock_path_table} , cycle_description, ignore_status);
    IF NOT ignore_status.normal THEN
      RETURN; {----->
    IFEND;

    IF (fmc$decrement_open_count IN work_list) AND (cycle_description^.global_file_information <> NIL) THEN
      work_list := work_list - $fmt$open_cleanup_work_list [fmc$decrement_open_count];
      #SPOIL (work_list);
      osp$decrement_locked_variable (cycle_description^.global_file_information^.open_count, 1, open_count,
            error);
    IFEND;

    IF fmc$free_static_label IN work_list THEN
      work_list := work_list - $fmt$open_cleanup_work_list [fmc$free_static_label];
      #SPOIL (work_list);
      IF cycle_description^.attached_file AND (cycle_description^.system_file_label.static_label <> NIL) THEN
        FREE cycle_description^.system_file_label.static_label IN osv$job_pageable_heap^;
      IFEND;
    IFEND;

    IF (fmc$clear_open_lock IN work_list) AND (cycle_description^.global_file_information <> NIL) THEN
      work_list := work_list - $fmt$open_cleanup_work_list [fmc$clear_open_lock];
      #SPOIL (work_list);
      osp$clear_job_signature_lock (cycle_description^.global_file_information^.open_lock);
    IFEND;

    fmp$unlock_path_table;

  PROCEND fmp$cleanup_open;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$detach_all_tape_files', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$detach_all_tape_files;

    VAR
      ignore_status: ost$status,
      index: integer,
      local_status: ost$status,
      previous_last_tape_list_entry: fst$path_handle_name,
      tape_file_list: array [1 .. 5] of fst$path_handle_name;

?? TITLE := 'get_tape_file_list', EJECT ??

    PROCEDURE get_tape_file_list
      (VAR tape_file_list: array [1 .. * ] of fst$path_handle_name);

      VAR
        cdu: ^fmt$cycle_description_unit,
        entry: integer,
        entry_p: ^fmt$cycle_description,
        tape_file_list_index: integer;

      FOR tape_file_list_index := 1 TO UPPERBOUND (tape_file_list) DO
        tape_file_list [tape_file_list_index] := osc$null_name;
      FOREND;
      tape_file_list_index := 0;

      fmp$lock_path_table (local_status);
      IF NOT local_status.normal THEN
        osp$generate_log_message ($pmt$ascii_logset [pmc$job_log, pmc$system_log], local_status,
              ignore_status);
        RETURN; {----->
      IFEND;

      cdu := fmv$initial_cdu_pointer;

    /get_tape_list/
      WHILE cdu <> NIL DO
        FOR entry := 1 TO #SIZE (cdu^.entry_assignment^) DO
          IF cdu^.entry_assignment^ (entry) = fmc$entry_assigned THEN
            entry_p := ^cdu^.entries^ [entry];
            IF (entry_p^.attached_file) AND (entry_p^.device_class = rmc$magnetic_tape_device) THEN
              tape_file_list_index := tape_file_list_index + 1;
              clp$construct_path_handle_name (entry_p^.path_handle, tape_file_list [tape_file_list_index]);
              IF tape_file_list_index >= UPPERBOUND (tape_file_list) THEN
                EXIT /get_tape_list/; {----->
              IFEND;
            IFEND;
          IFEND;
        FOREND;
        cdu := cdu^.next_cycle_description_unit;
      WHILEND /get_tape_list/;

      fmp$unlock_path_table;

    PROCEND get_tape_file_list;
?? OLDTITLE ??
?? EJECT ??

    previous_last_tape_list_entry := 'LAST_TAPE_ENTRY?';
    REPEAT
      get_tape_file_list (tape_file_list);
      IF tape_file_list [1] = osc$null_name THEN
        RETURN; {----->
      IFEND;
      index := 1;
      WHILE (index <= UPPERBOUND (tape_file_list)) AND (tape_file_list [index] <> osc$null_name) DO
        amp$return (tape_file_list [index], local_status);
        IF NOT local_status.normal THEN
          osp$generate_log_message ($pmt$ascii_logset [pmc$job_log, pmc$system_log], local_status,
                ignore_status);
        IFEND;
        index := index + 1;
      WHILEND;
      IF tape_file_list [UPPERBOUND (tape_file_list)] = previous_last_tape_list_entry THEN
        osp$set_status_abnormal (amc$access_method_id, fme$system_error,
              ' Unable to detach tape files in FMP$DETACH_ALL_TAPE_FILES', local_status);
        osp$generate_log_message ($pmt$ascii_logset [pmc$job_log, pmc$system_log], local_status,
              ignore_status);
        RETURN; {----->
      IFEND;
      previous_last_tape_list_entry := tape_file_list [UPPERBOUND (tape_file_list)];
    UNTIL (tape_file_list [UPPERBOUND (tape_file_list)] = osc$null_name);

  PROCEND fmp$detach_all_tape_files;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$end_new_open_processing', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$end_new_open_processing
    (    path_handle: fmt$path_handle;
     VAR status: ost$status);

    VAR
      cycle_description: ^fmt$cycle_description,
      label_header: ^fmt$static_label_header;

    fmp$locate_cd_via_path_handle (path_handle, TRUE {lock_path_table} , cycle_description, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

  /path_table_locked/
    BEGIN
      IF cycle_description^.attached_file THEN
        cycle_description^.system_file_label.file_previously_opened := TRUE;
        IF cycle_description^.permanent_file
{     } AND ((cycle_description^.device_class = rmc$mass_storage_device)
{       } OR (cycle_description^.device_class = rmc$magnetic_tape_device)) THEN
          fmp$catalog_system_file_label (^cycle_description^.system_file_label,
                cycle_description^.job_routing_label, cycle_description^.job_routing_label_length,
                cycle_description^.apfid, pfc$append, status);
          IF status.normal THEN
            cycle_description^.system_file_label_catalogued := TRUE;
          ELSE
            cycle_description^.system_file_label.file_previously_opened := FALSE;
            EXIT /path_table_locked/; {----->
          IFEND;
        IFEND;

        IF cycle_description^.system_file_label.static_label <> NIL THEN
          RESET cycle_description^.system_file_label.static_label;
          NEXT label_header IN cycle_description^.system_file_label.static_label;
          label_header^.file_previously_opened := TRUE;
          RESET cycle_description^.system_file_label.static_label;
        IFEND;
      IFEND; {attached_file}
    END /path_table_locked/;

    fmp$unlock_path_table;

  PROCEND fmp$end_new_open_processing;

?? TITLE := 'FUNCTION [XDCL, #GATE] fmp$file_is_open', EJECT ??
*copy fmh$file_is_open

  FUNCTION [XDCL, #GATE] fmp$file_is_open
    (    local_file_name: amt$local_file_name): boolean;

    VAR
      local_status: ost$status,
      cycle_description: ^fmt$cycle_description,
      open_count: integer;

    fmp$get_cycle_description (local_file_name, cycle_description, local_status);
    IF NOT local_status.normal THEN
      fmp$file_is_open := FALSE;
      RETURN; {----->
    IFEND;

    osp$fetch_locked_variable (cycle_description^.global_file_information^.open_count, open_count);
    fmp$file_is_open := open_count <> 0;

    fmp$unlock_path_table;

  FUNCEND fmp$file_is_open;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$get_device_class', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$get_device_class
    (    path_handle: fmt$path_handle;
     VAR device_assigned: boolean;
     VAR device_class: rmt$device_class;
     VAR status: ost$status);

    CONST
      lock_path_table = TRUE;

    VAR
      cycle_description: ^fmt$cycle_description;

    fmp$locate_cd_via_path_handle (path_handle, lock_path_table, cycle_description, status);
    IF status.normal THEN
      IF cycle_description^.attached_file THEN
        device_assigned := TRUE;
        device_class := cycle_description^.device_class;
      IFEND;
      fmp$unlock_path_table;
    IFEND;

  PROCEND fmp$get_device_class;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$get_device_class_and_sfid', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$get_device_class_and_sfid
    (    file: fst$file_reference;
     VAR device_class: rmt$device_class;
     VAR sfid: gft$system_file_identifier;
     VAR status: ost$status);

    VAR
      cycle_description: ^fmt$cycle_description;

    device_class := rmc$mass_storage_device;
    sfid := gfv$null_sfid;

    fmp$get_cycle_description (file, cycle_description, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF cycle_description^.attached_file THEN
      device_class := cycle_description^.device_class;
      CASE cycle_description^.device_class OF
      = rmc$magnetic_tape_device, rmc$mass_storage_device =
        sfid := cycle_description^.system_file_id;
      ELSE
      CASEND;
    ELSE
      osp$set_status_abnormal (amc$access_method_id, fme$system_error, ' NOT a local or attached file',
            status);
    IFEND;

    fmp$unlock_path_table;

  PROCEND fmp$get_device_class_and_sfid;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$get_jl_pointer', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$get_jl_pointer
    (    file: fst$file_reference;
         append: boolean;
     VAR jl_ptr: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      jl_size: 0 .. 80000000(16),
      cycle_description: ^fmt$cycle_description,
      header: ^fmt$static_label_header,
      new_job_routing_label: ^SEQ ( * ),
      pva_ptr: ^cell;

  /begin_end/
    BEGIN
      fmp$get_cycle_description (file, cycle_description, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;

      IF NOT (cycle_description^.attached_file AND (cycle_description^.device_class =
            rmc$mass_storage_device)) THEN
        osp$set_status_abnormal (amc$access_method_id, fme$system_error,
              ' not an attached MS file in fmp$get_jl_pointer', status);
        EXIT /begin_end/; {----->
      IFEND;

      IF append THEN
        IF cycle_description^.job_routing_label = NIL THEN
          ALLOCATE cycle_description^.job_routing_label: [[REP jmc$maximum_system_label_info OF cell]] IN
                osv$job_pageable_heap^;

          cycle_description^.job_routing_label_length := jmc$maximum_system_label_info;
        ELSEIF cycle_description^.job_routing_label_length < jmc$maximum_system_label_info THEN
          ALLOCATE new_job_routing_label: [[REP jmc$maximum_system_label_info OF cell]] IN
                osv$job_pageable_heap^;
          i#move (cycle_description^.job_routing_label, new_job_routing_label,
                cycle_description^.job_routing_label_length);
          FREE cycle_description^.job_routing_label IN osv$job_pageable_heap^;
          cycle_description^.job_routing_label := new_job_routing_label;
          cycle_description^.job_routing_label_length := jmc$maximum_system_label_info;
        IFEND;
      ELSEIF cycle_description^.job_routing_label = NIL THEN
        osp$set_status_abnormal (amc$access_method_id, fme$system_error,
              ' job_routing_label NIL in fmp$get_jl_pointer', status);
        EXIT /begin_end/; {----->
      IFEND;

      IF NOT cycle_description^.permanent_file AND (cycle_description^.system_file_label.static_label <> NIL)
            THEN

{ store job_routing_label size in static_label header for use by
{ fmp$store_system_label

        RESET cycle_description^.system_file_label.static_label;
        NEXT header IN cycle_description^.system_file_label.static_label;
        IF header = NIL THEN
          osp$set_status_abnormal (amc$access_method_id, ame$damaged_file_attributes,
                ' in fmp$get_jl_pointer', status);
          EXIT /begin_end/; {----->
        IFEND;
        header^.job_routing_label_size := cycle_description^.job_routing_label_length;
      IFEND;

      pva_ptr := cycle_description^.job_routing_label;

      jl_size := cycle_description^.job_routing_label_length;

      i#build_adaptable_seq_pointer (#RING (pva_ptr), #SEGMENT (pva_ptr), #OFFSET (pva_ptr),
            jl_size, 0, jl_ptr);
    END /begin_end/;

    fmp$unlock_path_table;
  PROCEND fmp$get_jl_pointer;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$get_system_file_id', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$get_system_file_id
    (    file: fst$file_reference;
     VAR system_file_id: gft$system_file_identifier;
     VAR status: ost$status);

    VAR
      cycle_description: ^fmt$cycle_description;

    fmp$get_cycle_description (file, cycle_description, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF cycle_description^.attached_file THEN
      CASE cycle_description^.device_class OF
      = rmc$magnetic_tape_device, rmc$mass_storage_device =
        system_file_id := cycle_description^.system_file_id;
      ELSE
        osp$set_status_abnormal (amc$access_method_id, fme$system_error, ' Improper device class', status);
      CASEND;
    ELSE
      osp$set_status_abnormal (amc$access_method_id, fme$system_error, ' NOT an attached file', status);
    IFEND;

    fmp$unlock_path_table;

  PROCEND fmp$get_system_file_id;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$get_path_table_cycle_info', EJECT ??
*copy fmh$get_path_table_cycle_info
{This routine is only called for permanent files.

  PROCEDURE [XDCL, #GATE] fmp$get_path_table_cycle_info
    (    inhibit_locking_pt: boolean;
     VAR {i/o} evaluated_file_reference: fst$evaluated_file_reference;
     VAR cycle_info: fmt$path_table_cycle_info;
     VAR status: ost$status);

    VAR
      cycle_description: ^fmt$cycle_description,
      header_pointer: ^fmt$static_label_header,
      i: integer,
      ignore_process_pt_results: bat$process_pt_results,
      ignore_status: ost$status,
      process_pt_work_list: bat$process_pt_work_list;

    status.normal := TRUE;

    cycle_info.path_registered := FALSE;
    cycle_info.cycle_device_info.device_assigned := FALSE;
    cycle_info.cycle_attachment_info.cycle_attached := FALSE;
    cycle_description := NIL;
    cycle_info.cycle_device_info.cycle_formerly_opened_info.cycle_previously_opened := FALSE;

    {
    { bac$resolve_pf_in_pt is here for the file server, to resolve to the
    { cycle that bam knows about before going to the server mainframe.
    {
    process_pt_work_list := $bat$process_pt_work_list [bac$resolve_path, bac$return_cycle_description,
          bac$resolve_pf_in_pt];
    IF inhibit_locking_pt THEN
      { must have been called by attach or create and they set the lock }
      { if the catalogs are going to be locked also }
      process_pt_work_list := process_pt_work_list + $bat$process_pt_work_list [bac$inhibit_locking_pt];
    IFEND;
    fmp$process_pt_request (process_pt_work_list, osc$null_name, evaluated_file_reference, cycle_description,
          ignore_process_pt_results, status);

    IF cycle_description <> NIL THEN

    /get_path_table_cycle_info/
      BEGIN
        cycle_info.path_registered := TRUE;
        cycle_info.cycle_number := evaluated_file_reference.cycle_reference.cycle_number;

        cycle_info.setfa_access_modes.selector := fsc$permitted_access_modes;
        IF cycle_description^.dynamic_setfa_entries <> NIL THEN

          IF cycle_description^.dynamic_setfa_entries^.access_modes_specified THEN
            cycle_info.setfa_access_modes.selector := fsc$specific_access_modes;
            #UNCHECKED_CONVERSION (cycle_description^.dynamic_setfa_entries^.access_modes,
                  cycle_info.setfa_access_modes.value);
          IFEND;
        IFEND;
        IF cycle_description^.attached_file THEN
          IF cycle_description^.permanent_file THEN
            pfp$check_device_availability (cycle_description^.apfid, status);
            IF NOT status.normal THEN
              EXIT /get_path_table_cycle_info/; {----->
            IFEND;
          IFEND;
          cycle_info.cycle_attachment_info.cycle_attached := TRUE;
          cycle_info.cycle_attachment_info.password_protected := cycle_description^.password_protected;
          cycle_info.cycle_attachment_info.allowed_access := cycle_description^.attached_access_modes;
          IF cycle_description^.device_class = rmc$magnetic_tape_device THEN
            cycle_info.cycle_attachment_info.required_sharing := $fst$file_access_options [];
          ELSE
            cycle_info.cycle_attachment_info.required_sharing := cycle_description^.attached_share_modes;
          IFEND;
          osp$fetch_locked_variable (cycle_description^.global_file_information^.open_count,
                cycle_info.cycle_attachment_info.open_count);
          cycle_info.cycle_device_info.device_assigned := TRUE;
          cycle_info.cycle_device_info.device_class := cycle_description^.device_class;
          IF cycle_description^.system_file_label.file_previously_opened THEN
            IF cycle_description^.system_file_label.static_label = NIL THEN
              cycle_info.cycle_device_info.cycle_formerly_opened_info.cycle_previously_opened := TRUE;
              cycle_info.cycle_device_info.cycle_formerly_opened_info.ring_attributes :=
                    fmv$system_file_attributes.static_label.ring_attributes;
              cycle_info.cycle_device_info.cycle_formerly_opened_info.ring_attributes_source :=
                    fmv$system_file_attributes.static_label.ring_attributes_source;
              EXIT /get_path_table_cycle_info/; {----->
            IFEND;
            RESET cycle_description^.system_file_label.static_label;
            NEXT header_pointer IN cycle_description^.system_file_label.static_label;
            IF header_pointer = NIL THEN
              osp$set_status_abnormal (amc$access_method_id, fme$system_error,
                    '- header_pointer NIL in fmp$get_path_table_cycle_info', status);
              EXIT /get_path_table_cycle_info/; {----->
            IFEND;
            IF header_pointer^.file_previously_opened THEN
              cycle_info.cycle_device_info.cycle_formerly_opened_info.cycle_previously_opened := TRUE;
              cycle_info.cycle_device_info.cycle_formerly_opened_info.ring_attributes :=
                    header_pointer^.ring_attributes;
              cycle_info.cycle_device_info.cycle_formerly_opened_info.ring_attributes_source :=
                    header_pointer^.ring_attributes_source;
            IFEND;
          IFEND;
        ELSE
          cycle_info.cycle_device_info.cycle_formerly_opened_info.cycle_previously_opened := FALSE;
        IFEND;

      END /get_path_table_cycle_info/;

      IF NOT inhibit_locking_pt THEN
        fmp$unlock_path_table;
      IFEND;

    IFEND; {cycle_description <> NIL}

  PROCEND fmp$get_path_table_cycle_info;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$job_exit', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$job_exit;

    VAR
      cdu: ^fmt$cycle_description_unit,
      context: ^ost$ecp_exception_context,
      density: rmt$density,
      entry: integer,
      make_another_pass: boolean,
      pass: 1 .. 2,
      path_handle_name: fst$path_handle_name,
      reservation: rmt$tape_reservation,
      status: ost$status,
      volume_down: boolean;

    syp$push_inhibit_job_recovery;

    osp$establish_condition_handler (^job_exit_condition_handler, FALSE);

    status.normal := TRUE;
    make_another_pass := FALSE;
    PUSH context;

  /detach_all_files/
    BEGIN
      FOR pass := 1 TO 2 DO
        cdu := fmv$initial_cdu_pointer;
        WHILE cdu <> NIL DO
          FOR entry := 1 TO #SIZE (cdu^.entry_assignment^) DO
            IF cdu^.entry_assignment^ (entry) = fmc$entry_assigned THEN
              IF cdu^.entries^ [entry].attached_file THEN
                context^ := osv$initial_exception_context;
                REPEAT
                  return_file_at_job_exit (^cdu^.entries^ [entry], status);
                  IF osp$file_access_condition (status) THEN
                    IF pass = 1 THEN
                      make_another_pass := TRUE;
                    ELSE
                      context^.condition_status := status;
                      clp$construct_path_handle_name (cdu^.entries^ [entry].path_handle, path_handle_name);
                      context^.file.selector := osc$ecp_file_reference;
                      context^.file.file_reference := ^path_handle_name;
                      osp$enforce_exception_policies (context^);
                      status := context^.condition_status;
                    IFEND;
                  ELSE
                    cdu^.entry_assignment^ (entry) := fmc$entry_free;
                  IFEND;
                UNTIL status.normal OR (NOT osp$file_access_condition (status)) OR (pass = 1) OR
                      (NOT context^.wait);
              ELSE
                cdu^.entry_assignment^ (entry) := fmc$entry_free;
              IFEND; {attached_file}
            IFEND; {entry_assigned}
          FOREND;
          cdu := cdu^.next_cycle_description_unit;
        WHILEND;
        IF pass = 1 THEN
          { perform explicit release of tape resource

          FOR density := rmc$800 TO rmc$maximum_density DO
            reservation [density] := UPPERVALUE (reservation [density]);
          FOREND;
          rmp$clear_explicit_reserve (reservation, status);
          REPEAT
            iop$delete_rvl_entries_via_ssn (status);
            IF NOT status.normal AND (status.condition = dme$unable_to_lock_tape_table) THEN
              pmp$wait (one_second, one_second);
            IFEND;
          UNTIL status.normal OR (status.condition <> dme$unable_to_lock_tape_table);
        IFEND;
        IF NOT make_another_pass THEN
          EXIT /detach_all_files/; {----->
        IFEND;
      FOREND;
    END /detach_all_files/;

    osp$disestablish_cond_handler;
    syp$pop_inhibit_job_recovery;
  PROCEND fmp$job_exit;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$ln_open_chapter', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$ln_open_chapter
    (    local_file_name: amt$local_file_name;
         chapter_number: dmt$chapter_number;
         validation_ring: ost$valid_ring;
         segment_attributes: ^array [ * ] of mmt$attribute_descriptor;
         pointer_kind: mmt$segment_pointer_kind;
     VAR segment_pointer: mmt$segment_pointer;
     VAR status: ost$status);

    CONST
      only_ms_files_supported = 'Only MS files are supported by fmp$ln_open_chapter';

    VAR
      cycle_description: ^fmt$cycle_description,
      evaluated_file_reference: fst$evaluated_file_reference,
      ignore_file_registered: boolean,
      ignore_process_pt_results: bat$process_pt_results;

    status.normal := TRUE;

  /begin_end/
    BEGIN
      fmp$evaluate_path (local_file_name, $bat$process_pt_work_list
            [bac$resolve_path, bac$resolve_to_catalog, bac$return_cycle_description],
            evaluated_file_reference, cycle_description, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;

      IF cycle_description = NIL THEN
        IF fsp$path_element (^evaluated_file_reference, 1) ^ = fsc$local THEN
          fmp$process_pt_request ($bat$process_pt_work_list [bac$record_path, bac$resolve_path,
                bac$create_cycle_description, bac$return_cycle_description], osc$null_name,
                evaluated_file_reference, cycle_description, ignore_process_pt_results, status);
          IF NOT status.normal OR (cycle_description = NIL) THEN
            IF status.normal THEN
              osp$set_status_abnormal (amc$access_method_id, fme$no_cycle_description, '', status);
            IFEND;
            RETURN; {----->
          IFEND;
          assign_device_class (rmc$mass_storage_device, cycle_description);
          create_temporary_file (NIL, {mass_storage_attributes} NIL, segment_attributes, cycle_description,
                status);
          IF NOT status.normal THEN
            EXIT /begin_end/; {----->
          IFEND;
        ELSE {NOT temporary file}
          osp$set_status_abnormal (amc$access_method_id, fme$system_error,
                'Permanent files must be attached before calling fmp$ln_open_chapter', status);
          RETURN; {----->
        IFEND;
      ELSEIF cycle_description^.attached_file THEN
        IF cycle_description^.device_class <> rmc$mass_storage_device THEN
          osp$set_status_abnormal (amc$access_method_id, fme$system_error, only_ms_files_supported, status);
          EXIT /begin_end/; {----->
        IFEND;
      ELSE
        osp$set_status_abnormal (amc$access_method_id, fme$system_error,
              'File must be attached if cycle_description exists in fmp$ln_open_chapter', status);
        EXIT /begin_end/; {----->
      IFEND;

      mmp$open_file_segment (cycle_description^.system_file_id, segment_attributes, pointer_kind,
            validation_ring, cycle_description^.file_space_limit_kind, segment_pointer, status);
      IF NOT status.normal THEN
        EXIT /begin_end/; {----->
      IFEND;

      cycle_description^.global_file_information^.eoi_set := FALSE;
      cycle_description^.system_file_label.file_previously_opened := TRUE;
    END /begin_end/;

    fmp$unlock_path_table;
  PROCEND fmp$ln_open_chapter;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$put_jl_pointer', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$put_jl_pointer
    (    file: fst$file_reference;
         write_label: boolean;
         jl_ptr: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      context: ^ost$ecp_exception_context,
      cycle_description: ^fmt$cycle_description,
      jl: ^cell,
      required_permission: pft$permit_options,
      volume_down: boolean;

?? NEWTITLE := 'CONDITION_HANDLER', EJECT ??

    PROCEDURE condition_handler
      (    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 status.normal THEN
        osp$set_status_from_condition (amc$access_method_id, condition, sfsa_p, status, ignore_status);
      IFEND;

    PROCEND condition_handler;
?? OLDTITLE ??
?? EJECT ??

    context := NIL;

  /begin_end/
    BEGIN
      fmp$get_cycle_description (file, cycle_description, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;

      IF NOT (cycle_description^.attached_file AND (cycle_description^.device_class =
            rmc$mass_storage_device)) THEN
        osp$set_status_abnormal (amc$access_method_id, fme$system_error,
              ' not an attached MS file in fmp$put_jl_pointer', status);
        EXIT /begin_end/; {----->
      IFEND;

      IF cycle_description^.job_routing_label = NIL THEN
        osp$set_status_abnormal (amc$access_method_id, fme$system_error, 'jrl NIL in fmp$put_jl_pointer',
              status);
        EXIT /begin_end/; {----->
      IFEND;

      cycle_description^.job_routing_label_length := i#current_sequence_position (jl_ptr);
      jl := jl_ptr;
      i#build_adaptable_seq_pointer (#RING (jl), #SEGMENT (jl), #OFFSET (jl),
            cycle_description^.job_routing_label_length, cycle_description^.job_routing_label_length,
            cycle_description^.job_routing_label);

      IF write_label AND cycle_description^.permanent_file THEN
        osp$establish_block_exit_hndlr (^condition_handler);
        pfp$begin_system_authority;
        IF cycle_description^.system_file_label.file_previously_opened THEN
          required_permission := pfc$control;
        ELSEIF fsc$append IN cycle_description^.attached_access_modes THEN
          required_permission := pfc$append;
        ELSE
          osp$set_status_condition (pfe$unknown_permanent_file, status);
          osp$append_status_file (osc$status_parameter_delimiter, file, status);
          EXIT /begin_end/ {----->
        IFEND;
        REPEAT
          fmp$catalog_system_file_label (^cycle_description^.system_file_label,
                cycle_description^.job_routing_label, cycle_description^.job_routing_label_length,
                cycle_description^.apfid, required_permission, status);
          IF NOT status.normal 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;
          IFEND;
        UNTIL status.normal OR (NOT osp$file_access_condition (status)) OR (NOT context^.wait);
        pfp$end_system_authority;
        osp$disestablish_cond_handler;
        IF status.normal THEN
          cycle_description^.system_file_label_catalogued := TRUE;
        IFEND;
      IFEND;
    END /begin_end/;

    fmp$unlock_path_table;
  PROCEND fmp$put_jl_pointer;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$record_open_cycle_info', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$record_open_cycle_info
    (    path_handle: fmt$path_handle;
         validation_ring: ost$valid_ring;
         access_level: amt$access_level;
         preserved_attributes: bat$static_label_attributes;
         instance_attributes: bat$instance_attributes;
         cd_attachment_options: fmt$cd_attachment_options;
         open_count: integer;
         device_class: rmt$device_class;
     VAR open_cleanup_work_list: {i/o} fmt$open_cleanup_work_list;
     VAR global_file_information: ^bat$global_file_information;
     VAR segment_pointer: ^cell;
     VAR system_file_label: ^fmt$system_file_label;
     VAR status: ost$status);

    VAR
      caller_id: ost$caller_identifier,
      cycle_description: ^fmt$cycle_description,
      eoi: amt$file_byte_address,
      fetch_status: ost$status,
      fetched_eoi: ost$segment_length,
      label_header: ^fmt$static_label_header,
      limit: sft$limit,
      mm_segment_pointer: mmt$segment_pointer,
      path: fst$path,
      path_size: fst$path_size,
      segment_attributes: ^array [1 .. * ] of mmt$attribute_descriptor,
      segment_ring: ost$valid_ring;

    #CALLER_ID (caller_id);
    status.normal := TRUE;

    fmp$locate_cd_via_path_handle (path_handle, TRUE {lock_path_table} , cycle_description, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

  /begin_end/
    BEGIN
      IF cycle_description^.attached_file THEN
        IF device_class = rmc$mass_storage_device THEN
          PUSH segment_attributes: [mm_ring_numbers_index .. mm_transfer_size_index];
          establish_segment_attributes (access_level, validation_ring, instance_attributes.static_label,
                instance_attributes.dynamic_label.access_mode, cd_attachment_options, segment_attributes,
                segment_ring);
          IF (open_count = 1) AND (preserved_attributes.file_limit_source <>
                fmv$system_file_attributes.static_label.file_limit_source) AND
                (preserved_attributes.file_limit <> fmv$system_file_attributes.static_label.file_limit) THEN
            dmp$set_file_limit (cycle_description^.system_file_id, preserved_attributes.file_limit, status);
            IF NOT status.normal THEN
              EXIT /begin_end/; {----->
            IFEND;
          IFEND;
        IFEND;
      ELSE
        assign_device_class (device_class, cycle_description);
        IF device_class = rmc$mass_storage_device THEN
          PUSH segment_attributes: [mm_ring_numbers_index .. mm_transfer_size_index];
          establish_segment_attributes (access_level, validation_ring, instance_attributes.static_label,
                instance_attributes.dynamic_label.access_mode, cd_attachment_options, segment_attributes,
                segment_ring);
          create_temporary_file (^preserved_attributes, {mass_storage_attributes} NIL, NIL, cycle_description,
                status);
          IF NOT status.normal THEN
            cycle_description^.attached_file := FALSE;
            EXIT /begin_end/; {----->
          IFEND;
        IFEND;
      IFEND;

      global_file_information := cycle_description^.global_file_information;
      IF open_count = 1 THEN
        { preserve global file information
        { maximum amount of data that may be written in a block }
        global_file_information^.max_data_size := preserved_attributes.max_block_length;
        { total size of a block - header to header }
        global_file_information^.max_block_size := global_file_information^.max_data_size +
              #SIZE (bat$block_header);
        { adjust total block size to word boundary if necessary }
        IF global_file_information^.max_block_size MOD 8 <> 0 THEN
          global_file_information^.max_block_size := (((global_file_information^.max_block_size DIV 8) *
                8) + 8);
        IFEND;

        global_file_information^.min_block_length := preserved_attributes.min_block_length;
        global_file_information^.max_record_length := preserved_attributes.max_record_length;
        global_file_information^.file_limit := preserved_attributes.file_limit;
        global_file_information^.padding_character := preserved_attributes.padding_character;
        global_file_information^.record_delimiting_character :=
              preserved_attributes.record_delimiting_character;
      IFEND;


      IF NOT cycle_description^.system_file_label.file_previously_opened THEN

{ File_previously_opened is set to TRUE in bap$end_new_open_processing when
{ the label is saved after the open has finished.

        fmp$put_label_attributes (preserved_attributes, cycle_description^.system_file_label);
        IF (cycle_description^.system_file_label.static_label <> NIL) THEN
          open_cleanup_work_list := open_cleanup_work_list +
                $fmt$open_cleanup_work_list [fmc$free_static_label];
          #SPOIL (open_cleanup_work_list);
          RESET cycle_description^.system_file_label.static_label;
          NEXT label_header IN cycle_description^.system_file_label.static_label;
          IF cycle_description^.device_class = rmc$mass_storage_device THEN
            label_header^.job_routing_label_size := cycle_description^.job_routing_label_length;
          ELSE
            label_header^.job_routing_label_size := 0;
          IFEND;
        IFEND;
      IFEND;

      IF cycle_description^.device_class = rmc$mass_storage_device THEN

        IF sfv$dynamic_file_space_limits AND (cycle_description^.file_space_limit_kind <> sfc$no_limit) AND
              (pfc$append IN instance_attributes.dynamic_label.access_mode) THEN
          IF cycle_description^.file_space_limit_kind = sfc$perm_file_space_limit THEN
            sfp$get_job_limit (avc$pfs_limit_name, limit, status);
          ELSE {temp file space limit}
            sfp$get_job_limit (avc$tfs_limit_name, limit, status);
          IFEND;
          IF status.normal THEN
            IF limit.accumulator >= limit.job_abort_limit THEN
              fmp$get_path_string (path_handle, {lock_path_table} FALSE, path, path_size, {ignore} status);
              osp$set_status_abnormal ('AV', ame$file_space_limit_exceeded, '', status);
              osp$append_status_file (osc$status_parameter_delimiter, path (1, path_size), status);
              IF cycle_description^.file_space_limit_kind = sfc$perm_file_space_limit THEN
                osp$append_status_parameter (osc$status_parameter_delimiter, 'Permanent', status);
              ELSE {temp file space limit}
                osp$append_status_parameter (osc$status_parameter_delimiter, 'Temporary', status);
              IFEND;
              EXIT /begin_end/; {----->
            IFEND;
          ELSE
            status.normal := TRUE;
          IFEND;
        IFEND;

        mmp$open_file_segment (cycle_description^.system_file_id, segment_attributes, mmc$cell_pointer,
              segment_ring, cycle_description^.file_space_limit_kind, mm_segment_pointer, status);
        syp$hang_if_job_jrt_set (fmc$tjr_open_lnt);
        IF NOT status.normal THEN
          EXIT /begin_end/; {----->
        IFEND;

        segment_pointer := mm_segment_pointer.cell_pointer;

        { For mass storage, eoi_set controls whether eoi is retrieved from
        { memory management or global_file_information.
        { We are assuming that if the last open was for record access
        { (eoi_set=TRUE) then the gfi.eoi is correct, otherwise go to memory
        {  management and get eoi.

        IF NOT global_file_information^.eoi_set THEN
          mmp$get_segment_length (mm_segment_pointer.cell_pointer, caller_id.ring, fetched_eoi, fetch_status);
          eoi := fetched_eoi;
          IF fetch_status.normal THEN
            global_file_information^.eoi_byte_address := eoi;
          ELSE
            status := fetch_status;
            EXIT /begin_end/; {----->
          IFEND;
        IFEND;
        { set eoi_set to reflect whether this open was for record_access
        global_file_information^.eoi_set := ((access_level <> amc$segment) AND
              NOT (instance_attributes.static_label.file_organization IN amv$aam_file_organizations));

      ELSEIF cycle_description^.device_class = rmc$magnetic_tape_device THEN
        segment_pointer := NIL;
        IF NOT global_file_information^.eoi_set THEN
          global_file_information^.eoi_set := TRUE;
          global_file_information^.eoi_byte_address := mmv$max_segment_length;
        IFEND;
      ELSE
        segment_pointer := NIL;
      IFEND;

      system_file_label := ^cycle_description^.system_file_label;
    END /begin_end/;

    fmp$unlock_path_table;

  PROCEND fmp$record_open_cycle_info;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$request_mass_storage', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$request_mass_storage
    (    allocation_size: rmt$allocation_size;
         estimated_file_size: amt$file_byte_address;
         file_class: rmt$mass_storage_class;
         initial_volume: rmt$recorded_vsn;
         transfer_size: fst$transfer_size;
         volume_overflow_allowed: boolean;
     VAR evaluated_file_reference: {i/o} fst$evaluated_file_reference;
     VAR status: ost$status);

    VAR
      cycle_description: ^fmt$cycle_description,
      ignore_cd_created: boolean,
      mass_storage_attributes: ^fst$mass_storage_device_info;

    fmp$create_cycle_description ({return_cycle_description=} TRUE, evaluated_file_reference,
          ignore_cd_created, cycle_description, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

  /path_table_locked/
    BEGIN
      verify_device_assignment (evaluated_file_reference, rmc$mass_storage_device, cycle_description, status);
      IF NOT status.normal THEN
        EXIT /path_table_locked/; {----->
      IFEND;

      assign_device_class (rmc$mass_storage_device, cycle_description);

      PUSH mass_storage_attributes;

      mass_storage_attributes^.bytes_allocated := estimated_file_size;
      mass_storage_attributes^.resides_online := TRUE;
      mass_storage_attributes^.allocation_unit_size := allocation_size;
      mass_storage_attributes^.mass_storage_class := file_class;
      mass_storage_attributes^.initial_volume := initial_volume;
      mass_storage_attributes^.transfer_size := transfer_size;
      mass_storage_attributes^.volume_overflow_allowed := volume_overflow_allowed;

      create_temporary_file ({preserved_attributes} NIL, mass_storage_attributes, {segment_attributes} NIL,
            cycle_description, status);
    END /path_table_locked/;

    fmp$unlock_path_table;
  PROCEND fmp$request_mass_storage;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$request_null_device', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$request_null_device
    (    null_device_class: rmt$device_class;
     VAR evaluated_file_reference: {i/o} fst$evaluated_file_reference;
     VAR status: ost$status);

    VAR
      attached: boolean,
      cycle_description: ^fmt$cycle_description,
      ignore_cd_created: boolean;

    status.normal := TRUE;
    IF NOT ((null_device_class = rmc$null_device) OR (null_device_class IN rmv$null_device_set)) THEN
      osp$set_status_abnormal (amc$access_method_id, fme$system_error,
            'Non NULL device class passed to fmp$request_null_device.', status);
      RETURN; {----->
    IFEND;

    IF fsp$path_element (^evaluated_file_reference, 1) ^ <> fsc$local THEN
      osp$set_status_abnormal (amc$access_method_id, cle$only_permitted_on_loc_file, '', status);
      RETURN; {----->
    IFEND;

    IF evaluated_file_reference.path_handle_info.path_handle_present THEN
      fmp$is_file_attached (evaluated_file_reference.path_handle_info.path_handle, attached, status);
      IF NOT status.normal THEN
        RETURN; {----->
      ELSEIF attached THEN
        evaluated_file_reference.cycle_reference.specification := fsc$next_cycle;
        evaluated_file_reference.path_handle_info.path_handle_present := FALSE;
      IFEND;
    IFEND;

    fmp$create_cycle_description ({return_cycle_description=} TRUE, evaluated_file_reference,
          ignore_cd_created, cycle_description, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

  /path_table_locked/
    BEGIN
      verify_device_assignment (evaluated_file_reference, null_device_class, cycle_description, status);
      IF NOT status.normal THEN
        EXIT /path_table_locked/; {----->
      IFEND;

      assign_device_class (null_device_class, cycle_description);
      osp$generate_unique_binary_name (cycle_description^.system_file_label.descriptive_label.
            global_file_name, status);
      IF status.normal THEN
        cycle_description^.system_file_label.descriptive_label.internal_cycle_name :=
              cycle_description^.system_file_label.descriptive_label.global_file_name;
      IFEND;
    END /path_table_locked/;

    fmp$unlock_path_table;
  PROCEND fmp$request_null_device;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$request_terminal', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$request_terminal
    (    terminal_file_name_loc: ^amt$local_file_name;
         terminal_attributes: ^ift$connection_attributes;
     VAR evaluated_file_reference: {i/o} fst$evaluated_file_reference;
     VAR status: ost$status);

    VAR
      attached: boolean,
      cycle_description: ^fmt$cycle_description,
      ignore_cd_created: boolean;

    status.normal := TRUE;

    IF fsp$path_element (^evaluated_file_reference, 1) ^ <> fsc$local THEN
      osp$set_status_abnormal (amc$access_method_id, cle$only_permitted_on_loc_file, '', status);
      RETURN; {----->
    IFEND;

    IF evaluated_file_reference.path_handle_info.path_handle_present THEN
      fmp$is_file_attached (evaluated_file_reference.path_handle_info.path_handle, attached, status);
      IF NOT status.normal THEN
        RETURN; {----->
      ELSEIF attached THEN
        evaluated_file_reference.cycle_reference.specification := fsc$next_cycle;
        evaluated_file_reference.path_handle_info.path_handle_present := FALSE;
      IFEND;
    IFEND;

    fmp$create_cycle_description ({return_cycle_description=} TRUE, evaluated_file_reference,
          ignore_cd_created, cycle_description, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

  /path_table_locked/
    BEGIN
      IF (cycle_description <> NIL) AND ((cycle_description^.static_setfa_entries <> NIL) OR
            (cycle_description^.dynamic_setfa_entries <> NIL)) THEN
        bap$set_evaluated_file_abnormal (evaluated_file_reference, ame$file_known, 'fmp$request_terminal', '',
              status);
        EXIT /path_table_locked/; {----->
      IFEND;

      verify_device_assignment (evaluated_file_reference, rmc$terminal_device, cycle_description, status);
      IF NOT status.normal THEN
        EXIT /path_table_locked/; {----->
      IFEND;

      assign_device_class (rmc$terminal_device, cycle_description);

      IF terminal_file_name_loc <> NIL THEN
        cycle_description^.terminal_file_name := terminal_file_name_loc^;
      IFEND;

      IF terminal_attributes <> NIL THEN
        ALLOCATE cycle_description^.terminal_request: [1 .. UPPERBOUND (terminal_attributes^)] IN
              osv$job_pageable_heap^;

        cycle_description^.terminal_request^ := terminal_attributes^;
      IFEND;

    END /path_table_locked/;

    fmp$unlock_path_table;
  PROCEND fmp$request_terminal;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$return_file', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$return_file
    (    evaluated_file_reference: fst$evaluated_file_reference;
         implicit_detach: boolean;
         detachment_options: ^fst$detachment_options;
     VAR status: ost$status);

    VAR
      cycle_description: ^fmt$cycle_description,
      log_device_file: boolean,
      open_count: integer,
      path_handle_name: fst$path_handle_name;

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

    fmp$locate_cd_via_path_handle (evaluated_file_reference.path_handle_info.path_handle, TRUE
          {lock_path_table} , cycle_description, status);
    IF NOT status.normal THEN
      IF NOT implicit_detach THEN
        fsp$set_evaluated_file_abnormal (evaluated_file_reference, ame$file_not_known, amc$return_req, '',
              status);
      ELSE
        status.normal := TRUE; {an asyncronous task detached the file
      IFEND;
      RETURN; {----->
    IFEND;

  /path_table_locked/
    BEGIN
      IF cycle_description^.attached_file THEN
        osp$fetch_locked_variable (cycle_description^.global_file_information^.open_count, open_count);

        IF (open_count = 0) AND (NOT implicit_detach) THEN
          CASE cycle_description^.device_class OF
          = rmc$connected_file_device =
            clp$construct_path_handle_name (evaluated_file_reference.path_handle_info.path_handle,
                  path_handle_name);
            clp$return_connected_file (path_handle_name);
          = rmc$log_device =
            log_device_file := TRUE;
            fsp$set_evaluated_file_abnormal (evaluated_file_reference, ame$file_not_closed, amc$return_req,
                  '', status);
          = rmc$network_device =
            return_network_file (cycle_description, status);
          = rmc$rhfam_device =
            clp$construct_path_handle_name (evaluated_file_reference.path_handle_info.path_handle,
                  path_handle_name);
            rfp$delete_connection (path_handle_name, status);
            status.normal := TRUE; {ignore status
          ELSE
          CASEND;
        IFEND;
      IFEND;

      IF NOT log_device_file THEN
        fmp$delete_path_description (evaluated_file_reference, implicit_detach, {return_permanent_file} TRUE,
              detachment_options, status);
      IFEND;

    END /path_table_locked/;

    fmp$unlock_path_table;

  PROCEND fmp$return_file;

?? TITLE := 'PROCEDURE [XDCL, #GATE] fmp$set_attachment_options', EJECT ??

  PROCEDURE [XDCL, #GATE] fmp$set_attachment_options
    (    file: fst$file_reference;
         attachment_options: fmt$cd_attachment_options;
         p_volume_list: {input} ^rmt$volume_list;
     VAR status: ost$status);

    VAR
      attach_index: integer,
      current_volume_number: amt$volume_number,
      current_vsns: rmt$volume_descriptor,
      cycle_description: ^fmt$cycle_description,
      density: rmt$density,
      device_class: rmt$device_class,
      evaluated_file_reference: fst$evaluated_file_reference,
      label_type: amt$label_type,
      local_attachment_options: fmt$cd_attachment_options,
      number_of_volumes: amt$volume_number,
      p_stored_volume_list: ^rmt$volume_list,
      parameter_name: ost$name,
      requested_volume_attributes: iot$requested_volume_attributes,
      stored_index: integer,
      valid_volume_list: boolean,
      volume_overflow_allowed: boolean,
      write_ring: rmt$write_ring;

    status.normal := TRUE;

    cycle_description := NIL;
    fmp$evaluate_path (file, $bat$process_pt_work_list [bac$resolve_path, bac$resolve_to_catalog,
          bac$return_cycle_description], evaluated_file_reference, cycle_description, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF cycle_description^.device_class <> rmc$magnetic_tape_device THEN
      IF attachment_options.external_vsn_specified THEN
        parameter_name := 'EXTERNAL_VSN';
      ELSEIF attachment_options.recorded_vsn_specified THEN
        parameter_name := 'RECORDED_VSN';
      ELSEIF attachment_options.volume_overflow_allowed_spec THEN
        parameter_name := 'VOLUME_OVERFLOW_ALLOWED';
      ELSE
        parameter_name := osc$null_name;
      IFEND;
      IF parameter_name <> osc$null_name THEN
        bap$set_evaluated_file_abnormal (evaluated_file_reference, fse$invalid_attachment_spec, 'ATTACH_FILE',
              parameter_name, status);
        osp$append_status_parameter (osc$status_parameter_delimiter,
              amv$device_class_names [cycle_description^.device_class].
              name (1, amv$device_class_names [cycle_description^.device_class].size), status);
      IFEND;
    IFEND;

    IF cycle_description^.device_class <> rmc$mass_storage_device THEN
      IF attachment_options.free_behind_specified THEN
        parameter_name := 'FREE_BEHIND';
      ELSEIF attachment_options.job_write_concurrency_specified THEN
        parameter_name := 'JOB_WRITE_CONCURRENCY';
      ELSEIF attachment_options.private_read_specified THEN
        parameter_name := 'PRIVATE_READ';
      ELSEIF attachment_options.sequential_access_specified THEN
        parameter_name := 'SEQUENTIAL_ACCESS';
      ELSEIF attachment_options.transfer_size_specified THEN
        parameter_name := 'TRANSFER_SIZE';
      ELSE
        parameter_name := osc$null_name;
      IFEND;
      IF parameter_name <> osc$null_name THEN
        bap$set_evaluated_file_abnormal (evaluated_file_reference, fse$invalid_attachment_spec, 'ATTACH_FILE',
              parameter_name, status);
        osp$append_status_parameter (osc$status_parameter_delimiter,
              amv$device_class_names [cycle_description^.device_class].
              name (1, amv$device_class_names [cycle_description^.device_class].size), status);
      IFEND;
    IFEND;

    IF status.normal AND (p_volume_list <> NIL) THEN
      valid_volume_list := FALSE;
      dmp$get_tape_volume_information (cycle_description^.system_file_id, number_of_volumes,
            current_volume_number, current_vsns, density, write_ring, requested_volume_attributes,
            volume_overflow_allowed, label_type, status);
      IF status.normal THEN
        PUSH p_stored_volume_list: [1 .. number_of_volumes];
        dmp$get_tape_volume_list (cycle_description^.system_file_id, p_stored_volume_list, status);
        IF status.normal THEN

        /validate_volume_list/
          FOR attach_index := 1 TO UPPERBOUND (p_stored_volume_list^) DO
            IF (attach_index + UPPERBOUND (p_volume_list^) - 1) > UPPERBOUND (p_stored_volume_list^) THEN
              EXIT /validate_volume_list/; {----->
            IFEND;
            IF (p_volume_list^ [1].external_vsn = p_stored_volume_list^ [attach_index].external_vsn) AND
                  (p_volume_list^ [1].recorded_vsn = p_stored_volume_list^ [attach_index].recorded_vsn) THEN

            /validate_remaining_volumes/
              FOR stored_index := 2 TO UPPERBOUND (p_volume_list^) DO
                IF (p_volume_list^ [stored_index].external_vsn <>
                      p_stored_volume_list^ [attach_index + stored_index - 1].external_vsn) OR
                      (p_volume_list^ [stored_index].recorded_vsn <>
                      p_stored_volume_list^ [attach_index + stored_index - 1].recorded_vsn) THEN
                  EXIT /validate_volume_list/; {----->
                IFEND;
              FOREND /validate_remaining_volumes/;
              valid_volume_list := TRUE;

              { Only allow volume overflow if the last volume is included.

              volume_overflow_allowed := volume_overflow_allowed AND
                    ((attach_index + UPPERBOUND (p_volume_list^) - 1) = UPPERBOUND (p_stored_volume_list^));
              EXIT /validate_volume_list/; {----->
            IFEND;
          FOREND /validate_volume_list/;
          IF NOT valid_volume_list THEN
            bap$set_evaluated_file_abnormal (evaluated_file_reference, fse$invalid_volume_list, 'ATTACH_FILE',
                  '', status);
          IFEND;
        IFEND;
      IFEND;
    IFEND;

    IF status.normal THEN
      IF cycle_description^.cd_attachment_options = NIL THEN
        ALLOCATE cycle_description^.cd_attachment_options IN osv$job_pageable_heap^;
        cycle_description^.cd_attachment_options^ := attachment_options;
        IF (cycle_description^.attached_access_modes * $fst$file_access_options
              [fsc$append, fsc$shorten, fsc$modify]) = $fst$file_access_options [] THEN
          cycle_description^.cd_attachment_options^.job_write_concurrency_specified := FALSE;
        IFEND;
      ELSE
        local_attachment_options := cycle_description^.cd_attachment_options^;
        parameter_name := osc$null_name;
        IF attachment_options.free_behind_specified THEN
          IF NOT local_attachment_options.free_behind_specified THEN
            local_attachment_options.free_behind_specified := TRUE;
            local_attachment_options.free_behind := attachment_options.free_behind;
          ELSEIF attachment_options.free_behind <> local_attachment_options.free_behind THEN
            parameter_name := 'FREE_BEHIND';
          IFEND;
        IFEND;
        IF attachment_options.job_write_concurrency_specified AND
              (cycle_description^.attached_access_modes * $fst$file_access_options
              [fsc$append, fsc$shorten, fsc$modify] <> $fst$file_access_options []) THEN
          IF NOT local_attachment_options.job_write_concurrency_specified THEN
            local_attachment_options.job_write_concurrency_specified := TRUE;
            local_attachment_options.job_write_concurrency := attachment_options.job_write_concurrency;
          ELSEIF attachment_options.job_write_concurrency <>
                local_attachment_options.job_write_concurrency THEN
            parameter_name := 'JOB_WRITE_CONCURRENCY';
          IFEND;
        IFEND;
        IF attachment_options.private_read_specified THEN
          IF NOT local_attachment_options.private_read_specified THEN
            local_attachment_options.private_read_specified := TRUE;
            local_attachment_options.private_read := attachment_options.private_read;
          ELSEIF attachment_options.private_read <> local_attachment_options.private_read THEN
            parameter_name := 'PRIVATE_READ';
          IFEND;
        IFEND;
        IF attachment_options.sequential_access_specified THEN
          IF NOT local_attachment_options.sequential_access_specified THEN
            local_attachment_options.sequential_access_specified := TRUE;
            local_attachment_options.sequential_access := attachment_options.sequential_access;
          ELSEIF attachment_options.sequential_access <> local_attachment_options.sequential_access THEN
            parameter_name := 'SEQUENTIAL_ACCESS';
          IFEND;
        IFEND;
        IF attachment_options.transfer_size_specified THEN
          IF (NOT local_attachment_options.transfer_size_specified) THEN
            local_attachment_options.transfer_size_specified := TRUE;
            local_attachment_options.transfer_size := attachment_options.transfer_size;
          ELSEIF attachment_options.transfer_size <> local_attachment_options.transfer_size THEN
            parameter_name := 'TRANSFER_SIZE';
          IFEND;
        IFEND;
        IF attachment_options.volume_overflow_allowed_spec THEN
          IF NOT local_attachment_options.volume_overflow_allowed_spec THEN
            local_attachment_options.volume_overflow_allowed_spec := TRUE;
            local_attachment_options.volume_overflow_allowed := attachment_options.volume_overflow_allowed;
          ELSEIF attachment_options.volume_overflow_allowed <>
                local_attachment_options.volume_overflow_allowed THEN
            parameter_name := 'VOLUME_OVERFLOW_ALLOWED';
          IFEND;
        IFEND;
        IF parameter_name <> osc$null_name THEN
          bap$set_evaluated_file_abnormal (evaluated_file_reference, fse$redundant_attachment_spec,
                'ATTACH_FILE', parameter_name, status);
        ELSE
          cycle_description^.cd_attachment_options^ := local_attachment_options;
        IFEND;
      IFEND;
      IF status.normal AND (cycle_description^.device_class = rmc$magnetic_tape_device) THEN
        IF p_volume_list <> NIL THEN
          dmp$replace_tape_vsn_list (cycle_description^.system_file_id, p_volume_list,
                volume_overflow_allowed, status);
          IF status.normal THEN
            REPEAT
              iop$delete_rvl_entry (cycle_description^.system_file_id, status);
              IF NOT status.normal AND (status.condition = dme$unable_to_lock_tape_table) THEN
                pmp$wait (one_second, one_second);
              IFEND;
            UNTIL status.normal OR (status.condition <> dme$unable_to_lock_tape_table);
          IFEND;
          IF status.normal THEN
            REPEAT
              iop$create_rvl_entry (cycle_description^.system_file_id, density,
                    cycle_description^.system_file_label.descriptive_label.global_file_name,
                    evaluated_file_reference.path_handle_info.path_handle, rmv$requested_volume_attributes,
                    p_volume_list^, write_ring, status);
              IF NOT status.normal AND (status.condition = dme$unable_to_lock_tape_table) THEN
                pmp$wait (one_second, one_second);
              IFEND;
            UNTIL status.normal OR (status.condition <> dme$unable_to_lock_tape_table);
          IFEND;
          IF status.normal THEN
            cycle_description^.system_file_label.descriptive_label.internal_cycle_name :=
                  cycle_description^.system_file_label.descriptive_label.global_file_name;
          IFEND;
        ELSEIF attachment_options.volume_overflow_allowed_spec THEN
          dmp$replace_tape_vsn_list (cycle_description^.system_file_id, {p_volume_list} NIL,
                attachment_options.volume_overflow_allowed, status);
        IFEND;
      IFEND;
    IFEND;

    fmp$unlock_path_table;

  PROCEND fmp$set_attachment_options;

?? TITLE := 'PROCEDURE [INLINE] assign_device_class', EJECT ??

  PROCEDURE [INLINE] assign_device_class
    (    device_class: rmt$device_class;
         cycle_description: {i^/o^} ^fmt$cycle_description);

    IF cycle_description^.attached_file THEN
      RETURN; {----->
    IFEND;

    cycle_description^.attached_file := TRUE;
    cycle_description^.system_file_label.static_label := NIL;
    cycle_description^.system_file_label.file_previously_opened := FALSE;
    cycle_description^.system_file_label.descriptive_label := fmv$system_file_attributes.descriptive_label;
    cycle_description^.device_class := device_class;

    CASE cycle_description^.device_class OF
    = rmc$magnetic_tape_device =
      cycle_description^.file_space_limit_kind := sfc$no_limit;
      cycle_description^.job_routing_label := NIL;
      cycle_description^.job_routing_label_length := 0;
      cycle_description^.permanent_file := FALSE;
      cycle_description^.system_file_id := gfv$null_sfid;

    = rmc$mass_storage_device =
      cycle_description^.file_space_limit_kind := sfc$temp_file_space_limit;
      cycle_description^.job_routing_label := NIL;
      cycle_description^.job_routing_label_length := 0;
      cycle_description^.permanent_file := FALSE;
      cycle_description^.system_file_id := gfv$null_sfid;

    = rmc$terminal_device =
      cycle_description^.terminal_request := NIL;
      cycle_description^.terminal_command := NIL;
      cycle_description^.terminal_file_name := osc$null_name;

    ELSE
    CASEND;
  PROCEND assign_device_class;

?? TITLE := 'PROCEDURE [INLINE] create_temporary_file', EJECT ??

  PROCEDURE [INLINE] create_temporary_file
    (    preserved_attributes: ^bat$static_label_attributes;
         request_descriptor: ^fst$mass_storage_device_info;
         segment_attributes: ^array [ * ] of mmt$attribute_descriptor;
     VAR cycle_description: ^fmt$cycle_description;
     VAR status: ost$status);

    VAR
      caller_id: ost$caller_identifier,
      engineering_operation: boolean,
      entry_available: boolean,
      i: integer,
      file_attributes: array [dm_file_class_index .. dm_transfer_size_index] of dmt$new_file_attribute,
      file_class: string (1),
      file_share_selections: pft$share_selections,
      file_type: gft$file_kind,
      file_usage: pft$usage_selections;

    #CALLER_ID (caller_id);
    status.normal := TRUE;

    file_type := gfc$fk_job_local_file;
    file_usage := -$pft$usage_selections [];
    file_share_selections := $pft$share_selections [];
    file_attributes := dm_file_attributes;

    IF jmp$system_job () THEN
      file_attributes [dm_file_class_index].class := rmc$msc_system_critical_files;
    IFEND;

    IF preserved_attributes <> NIL THEN
      file_attributes [dm_clear_space_index].required := preserved_attributes^.clear_space;
      file_attributes [dm_preset_value_index].preset_value := preserved_attributes^.preset_value;
      file_attributes [dm_file_limit_index].limit := preserved_attributes^.file_limit;
    ELSEIF segment_attributes <> NIL THEN
      FOR i := LOWERBOUND (segment_attributes^) TO UPPERBOUND (segment_attributes^) DO
        CASE segment_attributes^ [i].keyword OF
        = mmc$kw_clear_space =
          file_attributes [dm_clear_space_index].required := segment_attributes^ [i].clear_space;
        = mmc$kw_max_segment_length =
          file_attributes [dm_file_limit_index].limit := segment_attributes^ [i].max_length;
        = mmc$kw_preset_value =
          file_attributes [dm_preset_value_index].preset_value :=
                mmv$preset_conversion_table [segment_attributes^ [i].preset_value];
        ELSE
        CASEND;
      FOREND;
    IFEND;

    IF request_descriptor <> NIL THEN
      file_attributes [dm_volume_overflow_index].overflow_allowed :=
            request_descriptor^.volume_overflow_allowed;
      file_attributes [dm_initial_volume_index].requested_volume.recorded_vsn :=
            request_descriptor^.initial_volume;

      IF request_descriptor^.allocation_unit_size <> rmc$unspecified_allocation_size THEN
        file_attributes [dm_allocation_size_index].requested_allocation_size :=
              request_descriptor^.allocation_unit_size;
      IFEND;

      IF request_descriptor^.transfer_size < LOWERVALUE (dmt$transfer_size) THEN
        file_attributes [dm_transfer_size_index].requested_transfer_size := LOWERVALUE (dmt$transfer_size);
      ELSEIF request_descriptor^.transfer_size > UPPERVALUE (dmt$transfer_size) THEN
        file_attributes [dm_transfer_size_index].requested_transfer_size := UPPERVALUE (dmt$transfer_size);
      ELSE
        file_attributes [dm_transfer_size_index].requested_transfer_size := request_descriptor^.transfer_size;
      IFEND;

      IF request_descriptor^.mass_storage_class <> rmc$unspecified_file_class THEN
        file_attributes [dm_file_class_index].class := request_descriptor^.mass_storage_class;
      ELSEIF request_descriptor^.initial_volume <> rmc$unspecified_vsn THEN
        avp$get_capability (avc$engineering_operation, avc$user, engineering_operation, status);
        status.normal := TRUE;
        IF (engineering_operation OR jmp$system_job () OR avp$system_administrator () OR
              (caller_id.ring <= osc$tsrv_ring)) THEN
          file_attributes [dm_file_class_index].class := rmc$unspecified_file_class;
        IFEND;
      IFEND;
    IFEND;

    IF status.normal THEN
      dmp$create_file_entry (file_type, file_usage, file_share_selections, dmc$minimum_file_share_his,
            ^file_attributes, {byte_address} 0, {assign_volume} TRUE,
            cycle_description^.system_file_label.descriptive_label.global_file_name,
            cycle_description^.system_file_id, status);
    IFEND;

    IF status.normal THEN
      cycle_description^.system_file_label.descriptive_label.internal_cycle_name :=
            cycle_description^.system_file_label.descriptive_label.global_file_name;
    ELSE
      IF status.condition = dme$file_class_not_valid THEN
        file_class := file_attributes [dm_file_class_index].class;
        osp$set_status_abnormal (rmc$resource_management_id, rme$file_class_not_valid,
              request_descriptor^.initial_volume, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, file_class, status);
      ELSEIF status.condition = dme$unable_to_create_fdt_entry THEN
        osp$set_status_condition (fse$temp_files_limit_reached, status);
      IFEND;
    IFEND;

  PROCEND create_temporary_file;

?? TITLE := 'PROCEDURE [INLINE] establish_segment_attributes', EJECT ??

  PROCEDURE [INLINE] establish_segment_attributes
    (    access_level: amt$access_level;
         validation_ring: ost$valid_ring;
         instance_static_attributes: bat$instance_static_attributes;
         access_mode: pft$usage_selections;
         cd_attachment_options: fmt$cd_attachment_options;
         segment_attributes: {i^/o^} ^array [1 .. * ] of mmt$attribute_descriptor;
     VAR ring: ost$valid_ring);

    IF (NOT (instance_static_attributes.file_organization IN amv$aam_file_organizations)) AND
          cd_attachment_options.transfer_size_specified THEN
      segment_attributes^ [mm_transfer_size_index].keyword := mmc$kw_ps_transfer_size;
      segment_attributes^ [mm_transfer_size_index].ps_transfer_size := cd_attachment_options.transfer_size;
    ELSE
      segment_attributes^ [mm_transfer_size_index].keyword := mmc$kw_null_keyword;
    IFEND;

    segment_attributes^ [mm_ring_numbers_index].keyword := mmc$kw_ring_numbers;
    CASE access_level OF
    = amc$segment =
      segment_attributes^ [mm_ring_numbers_index].r1 := instance_static_attributes.ring_attributes.r1;
      segment_attributes^ [mm_ring_numbers_index].r2 := instance_static_attributes.ring_attributes.r2;
      ring := validation_ring;

    = amc$record =
      IF instance_static_attributes.file_organization IN amv$aam_file_organizations THEN
        segment_attributes^ [mm_ring_numbers_index].r1 := 4;
        segment_attributes^ [mm_ring_numbers_index].r2 := 4;
        ring := 4;
      ELSE
        segment_attributes^ [mm_ring_numbers_index].r1 := 3;
        segment_attributes^ [mm_ring_numbers_index].r2 := 3;
        ring := 3;
      IFEND;

    = amc$physical =
      segment_attributes^ [mm_ring_numbers_index].r1 := validation_ring;
      segment_attributes^ [mm_ring_numbers_index].r2 := validation_ring;
      ring := validation_ring;

    ELSE
      ;
    CASEND;

    segment_attributes^ [mm_access_control_index].keyword := mmc$kw_segment_access_control;
    segment_attributes^ [mm_access_control_index].access_control.cache_bypass := FALSE;
    segment_attributes^ [mm_access_control_index].access_control.execute_privilege := osc$non_executable;
    segment_attributes^ [mm_access_control_index].access_control.read_privilege := osc$non_readable;
    segment_attributes^ [mm_access_control_index].access_control.write_privilege := osc$non_writable;
    IF read_access <= access_mode THEN
      segment_attributes^ [mm_access_control_index].access_control.read_privilege := osc$read_uncontrolled;
    IFEND;
    IF (write_access * access_mode) <> null_set THEN
      segment_attributes^ [mm_access_control_index].access_control.write_privilege := osc$write_uncontrolled;
      IF access_level = amc$record THEN
        segment_attributes^ [mm_access_control_index].access_control.read_privilege := osc$read_uncontrolled;
      IFEND;
    IFEND;
    IF execute_access <= access_mode THEN
      segment_attributes^ [mm_access_control_index].access_control.execute_privilege := osc$non_privileged;
    IFEND;

    segment_attributes^ [mm_software_attributes_index].keyword := mmc$kw_software_attributes;
    segment_attributes^ [mm_software_attributes_index].software_attri_set := $mmt$software_attribute_set [];
    IF NOT (pfc$append IN access_mode) THEN
      segment_attributes^ [mm_software_attributes_index].software_attri_set :=
            segment_attributes^ [mm_software_attributes_index].software_attri_set +
            $mmt$software_attribute_set [mmc$sa_no_append];
    IFEND;
    IF NOT (instance_static_attributes.file_organization IN amv$aam_file_organizations) THEN
      IF NOT cd_attachment_options.sequential_access_specified THEN
        IF access_level = amc$record THEN
          segment_attributes^ [mm_software_attributes_index].
                software_attri_set := segment_attributes^ [mm_software_attributes_index].
                software_attri_set + $mmt$software_attribute_set [mmc$sa_read_transfer_unit];
        IFEND;
      ELSEIF cd_attachment_options.sequential_access THEN
        segment_attributes^ [mm_software_attributes_index].software_attri_set :=
              segment_attributes^ [mm_software_attributes_index].software_attri_set +
              $mmt$software_attribute_set [mmc$sa_read_transfer_unit];
      IFEND;
      IF NOT cd_attachment_options.free_behind_specified THEN
        IF (access_level = amc$record) AND (instance_static_attributes.block_type = amc$system_specified) THEN
          segment_attributes^ [mm_software_attributes_index].
                software_attri_set := segment_attributes^ [mm_software_attributes_index].
                software_attri_set + $mmt$software_attribute_set [mmc$sa_free_behind];
        IFEND;
      ELSEIF cd_attachment_options.free_behind THEN
        segment_attributes^ [mm_software_attributes_index].software_attri_set :=
              segment_attributes^ [mm_software_attributes_index].software_attri_set +
              $mmt$software_attribute_set [mmc$sa_free_behind];
      IFEND;
    IFEND;

  PROCEND establish_segment_attributes;

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

{ PURPOSE:
{   This procedure handles those conditions that occur during job exit.

  PROCEDURE job_exit_condition_handler
    (    condition: pmt$condition;
         condition_information: ^pmt$condition_information;
         save_area: ^ost$stack_frame_save_area;
     VAR handler_status: ost$status);

    VAR
      continue: boolean;

    handler_status.normal := TRUE;

    CASE condition.selector OF
    = pmc$system_conditions, mmc$segment_access_condition, pmc$user_defined_condition =
      continue := TRUE;
    ELSE
      continue := FALSE;
    CASEND;

    IF continue THEN
      pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
    IFEND;
  PROCEND job_exit_condition_handler;

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

  PROCEDURE put_label_in_cd
    (    p_file_label: fmt$p_file_label;
         cycle_description: ^fmt$cycle_description;
         path_handle: fmt$path_handle;
     VAR status: ost$status);

    VAR
      label_size: integer,
      local_p_file_label: fmt$p_file_label,
      label_header: ^fmt$static_label_header;

    status.normal := TRUE;

    local_p_file_label := p_file_label;
    RESET local_p_file_label;
    NEXT label_header IN local_p_file_label;
    IF label_header^.unique_character = fmc$unique_label_id THEN
      IF label_header^.highest_attribute_present > 0 THEN
        IF label_header^.revision_level <> fmc$current_revision_level THEN
          bap$validate_compatibility (local_p_file_label, label_header, path_handle, FALSE, status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;
        IFEND;

        label_size := #SIZE (p_file_label^) - label_header^.job_routing_label_size;
        IF cycle_description^.system_file_label.static_label <> NIL THEN
          FREE cycle_description^.system_file_label.static_label IN osv$job_pageable_heap^;
        IFEND;
        ALLOCATE cycle_description^.system_file_label.static_label: [[REP label_size OF cell]] IN
              osv$job_pageable_heap^;
        i#move (local_p_file_label, cycle_description^.system_file_label.static_label, label_size);
        RESET cycle_description^.system_file_label.static_label;
        NEXT label_header IN cycle_description^.system_file_label.static_label;
        label_header^.revision_level := fmc$current_revision_level;
        IF label_header^.revision_level <> fmc$current_revision_level THEN
          fmp$verify_attribute_limits (cycle_description^.system_file_label.static_label, status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;
        IFEND;
      ELSE { highest_attribute_present = 0  (default label) }
        cycle_description^.system_file_label.static_label := NIL;
      IFEND;
    ELSE { unique_character <> % }
      osp$set_status_abnormal (amc$access_method_id, ame$damaged_file_attributes, 'put_label_in_cd', status);
    IFEND;
  PROCEND put_label_in_cd;

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

  PROCEDURE return_network_file
    (    cycle_description: ^fmt$cycle_description;
     VAR status: ost$status);

    VAR
      switch_complete: boolean;

    status.normal := TRUE;

    IF (cycle_description^.global_file_information^.device_dependent_info.network_global_file_information^.
          file_state = nac$normal) OR (cycle_description^.global_file_information^.device_dependent_info.
          network_global_file_information^.file_state = nac$nominal_normal) THEN
      nap$se_return_file (cycle_description^.global_file_information^.device_dependent_info.
            network_connection_id, status);
    ELSEIF cycle_description^.global_file_information^.device_dependent_info.network_global_file_information^.
          file_state = nac$simulated_connection_broken THEN
      nap$se_return_file (cycle_description^.global_file_information^.device_dependent_info.
            network_global_file_information^.backup_connection_id, status);
    ELSEIF (cycle_description^.global_file_information^.device_dependent_info.
          network_global_file_information^.file_state = nac$switch_offered) OR
          (cycle_description^.global_file_information^.device_dependent_info.network_global_file_information^.
          file_state = nac$nominal_conn_switch_offer) THEN
      nlp$cancel_switch_offer (cycle_description^.global_file_information^.device_dependent_info.
            network_global_file_information^.backup_connection_id, switch_complete, status);
      IF NOT status.normal THEN
        osp$system_error ('nlp$cancel_switch_offer failed', ^status);
        {! DEBUG}
      IFEND;
      IF NOT switch_complete THEN
        nap$se_return_file (cycle_description^.global_file_information^.device_dependent_info.
              network_global_file_information^.backup_connection_id, status);
      IFEND;
    IFEND;

    FREE cycle_description^.global_file_information^.device_dependent_info.network_global_file_information IN
          osv$task_shared_heap^;
  PROCEND return_network_file;

?? TITLE := 'PROCEDURE [INLINE] return_file_at_job_exit', EJECT ??

  PROCEDURE [INLINE] return_file_at_job_exit
    (    cycle_description: ^fmt$cycle_description;
     VAR status: ost$status);

    VAR
      detachment_options: fmt$detachment_options,
      path_handle_name: fst$path_handle_name,
      usage_selections: pft$usage_selections;

    status.normal := TRUE;

    CASE cycle_description^.device_class OF
    = rmc$magnetic_tape_device =
      IF cycle_description^.permanent_file THEN
        IF (cycle_description^.static_setfa_entries <> NIL) AND
              (NOT cycle_description^.system_file_label.file_previously_opened) THEN
          fmp$catalog_set_file_attributes (cycle_description, status);
          IF osp$file_access_condition (status) THEN {ignore any other status}
            RETURN; {----->
          IFEND;
        IFEND;

        #UNCHECKED_CONVERSION (cycle_description^.attached_access_modes, usage_selections);
        pfp$return_permanent_file (cycle_description^.apfid, cycle_description^.system_file_id,
              cycle_description^.device_class, usage_selections, status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
      ELSE
        detachment_options := fmv$default_detachment_options;
        detachment_options.device_class := rmc$magnetic_tape_device;
        detachment_options.physical_unload := TRUE;
        dmp$close_tape_volume (cycle_description^.system_file_id, detachment_options, status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
      IFEND;

    = rmc$mass_storage_device =
      IF cycle_description^.permanent_file THEN
        IF (cycle_description^.static_setfa_entries <> NIL) AND
              (NOT cycle_description^.system_file_label.file_previously_opened) THEN
          fmp$catalog_set_file_attributes (cycle_description, status);
          IF osp$file_access_condition (status) THEN {ignore any other status.
            RETURN; {----->
          IFEND;
        IFEND;

        #UNCHECKED_CONVERSION (cycle_description^.attached_access_modes, usage_selections);
        pfp$return_permanent_file (cycle_description^.apfid, cycle_description^.system_file_id,
              cycle_description^.device_class, usage_selections, status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
      ELSE
        IF (cycle_description^.system_file_id.residence = gfc$tr_job) THEN
          dmp$destroy_file (cycle_description^.system_file_id, cycle_description^.file_space_limit_kind,
                status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;
        IFEND;
      IFEND;

    = rmc$null_device =

    = rmc$network_device =
      return_network_file (cycle_description, status);
    = rmc$rhfam_device =
      clp$construct_path_handle_name (cycle_description^.path_handle, path_handle_name);
      rfp$delete_connection (path_handle_name, status);
    ELSE { terminal
      ;
    CASEND;
  PROCEND return_file_at_job_exit;

?? TITLE := 'PROCEDURE [INLINE] verify_device_assignment', EJECT ??

  PROCEDURE [INLINE] verify_device_assignment
    (    evaluated_file_reference: fst$evaluated_file_reference;
         required_device_class: rmt$device_class;
         cycle_description: ^fmt$cycle_description;
     VAR status: ost$status);

    status.normal := TRUE;

    IF cycle_description^.attached_file THEN
      IF cycle_description^.device_class <> required_device_class THEN
        bap$set_evaluated_file_abnormal (evaluated_file_reference, rme$device_assignment_conflict,
              'FMM$CYCLE_MANAGER', amv$device_class_names [cycle_description^.device_class].
              name (1, amv$device_class_names [cycle_description^.device_class].size), status);
        osp$append_status_parameter (osc$status_parameter_delimiter,
              amv$device_class_names [required_device_class].name
              (1, amv$device_class_names [required_device_class].size), status);
      ELSE
        bap$set_evaluated_file_abnormal (evaluated_file_reference, rme$redundant_device_assignment,
              'FMM$CYCLE_MANAGER', amv$device_class_names [cycle_description^.device_class].
              name (1, amv$device_class_names [cycle_description^.device_class].size), status);
      IFEND;
    IFEND;

  PROCEND verify_device_assignment;
?? OLDTITLE ??
MODEND fmm$cycle_manager;
