?? NEWTITLE := 'NOS/VE : File Management : Path Table Manager' ??
MODULE fmm$path_table_manager;
?? RIGHT := 110 ??

{  PURPOSE:
{    This module is responsible for all processing of the
{    file systems path_table.  All procedures which directly manage the
{    tree are located here to isolate knowledge of how the tree is managed
{    from those processes which act upon an individual node.
{
{  DESIGN:
{    The path_table is a binary tree.
{
{    All searches, additions and deletions of nodes (path_description_entry's)
{    or their associated cycle_objects (also path_description_entry's)
{    require that the entire path_table be locked for the duration.
{
{    Additions of nodes to the table will be done based on a provided
{    path_element array and cycle_number if the node will be a cycle_object.
{    Upon addition to the path_table, a path_handle containing an offset
{    into the segment containing the path_table and a unique
{    assignment_counter for use in validation when re-entering the path_table
{    later will be passed back.
{
{    All searchs and additions will begin at the root of the tree
{    (fmv$path_table_entry_point).
{
{    All procedures merely updating an already created entry will search
{    based on the path_handle passed back when the entry was created.
{

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc amc$condition_code_limits
*copyc pft$password_selector
*copyc ame$lfn_program_actions
*copyc ame$put_program_actions
*copyc ame$ring_validation_errors
*copyc amt$local_file_name
*copyc bat$process_pt_results
*copyc bat$process_pt_work_list
*copyc bat$static_label_attributes
*copyc clc$standard_file_names
*copyc cle$ecc_file_reference
*copyc cyc$max_string_size
*copyc cyt$string_index
*copyc fmc$cycle_table_allocation_size
*copyc fmc$entry_assigned
*copyc fmc$number_of_init_cycle_descs
*copyc fmc$number_of_init_path_descs
*copyc fmc$path_table_allocation_size
*copyc fmc$pde_unique_identifier
*copyc fmc$statistics_max_path_depth
*copyc fmc$test_jr_constants
*copyc fme$file_management_errors
*copyc fmt$cycle_description
*copyc fmt$cycle_description_unit
*copyc fmt$detachment_options
*copyc fmt$global_file_entries
*copyc fmt$path_description_entry
*copyc fmt$path_description_unit
*copyc fmt$path_handle
*copyc fmt$static_label_header
*copyc fsc$local
*copyc fsc$max_path_elements
*copyc fsc$maximum_cycle_number
*copyc fse$path_exception_conditions
*copyc fst$cycle_number
*copyc fst$cycle_reference
*copyc fst$detachment_options
*copyc fst$evaluated_file_reference
*copyc fst$goi_information_request
*copyc fst$goi_object_information
*copyc fst$path
*copyc fst$path_element
*copyc fst$path_index
*copyc fst$path_resolution
*copyc fst$resolved_file_reference
*copyc mme$condition_codes
*copyc osd$integer_limits
*copyc osd$random_name
*copyc osd$virtual_address
*copyc oss$task_shared
*copyc ost$signature_lock
*copyc ost$status
*copyc pfe$error_condition_codes
*copyc pfe$get_object_info_errors
*copyc pfe$internal_error_conditions
?? POP ??

*copyc avp$ring_min
*copyc bap$free_tape_label_sequences
*copyc bap$set_evaluated_file_abnormal
*copyc bap$set_file_reference_abnormal
*copyc clp$construct_path_handle_name
*copyc clp$convert_file_ref_to_string
*copyc clp$convert_integer_to_string
*copyc clp$trimmed_string_size
*copyc clp$validate_local_file_name
*copyc clp$validate_new_file_name
*copyc dmp$close_tape_volume
*copyc dmp$destroy_file
*copyc dmp$fetch_eoi
*copyc dmp$get_stored_fmd
*copyc dmp$get_stored_fmd_header_info
*copyc dmp$setup_tape_init_in_progress
*copyc fmp$catalog_set_file_attributes
*copyc fmp$free_terminal_request
*copyc fmp$get_attached_tape_info
*copyc fmp$locate_pde_via_path_handle
*copyc fmp$merge_setfa_entries

  PROCEDURE hide_xrefs_copied_by_inlines;

{fmp$lock_path_table & fmp$unlock_path_table

*copyc fmv$path_table_lock

{fmp$get_list_of_connected_files

*copyc fmp$get_path_string
  PROCEND hide_xrefs_copied_by_inlines;
*copyc fmp$lock_path_table
*copyc fmp$unlock_path_table
*copyc fmp$get_list_of_connected_files
*copyc fsp$path_element
*copyc fsp$set_evaluated_file_abnormal
*copyc i#move
*copyc osp$append_status_file
*copyc osp$append_status_integer
*copyc osp$append_status_parameter
*copyc osp$fetch_locked_variable
*copyc osp$file_access_condition
*copyc osp$randomize_name
*copyc osp$recoverable_system_error
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc osp$system_error
*copyc osp$test_sig_lock
*copyc pfp$convert_fs_to_pft$path
*copyc pfp$find_directory_array
*copyc pfp$find_next_info_record
*copyc pfp$get_attached_device_info
*copyc pfp$resolve_path
*copyc pfp$return_permanent_file

*copyc clv$local_catalog_handle_name
*copyc clv$open_position_designator
*copyc dmv$initialize_tape_volume
*copyc fmv$entry_assigned_free_select
*copyc fmv$global_file_information
*copyc fmv$static_label_header
*copyc fmv$system_file_attributes
*copyc fsv$default_job_environ_info
*copyc fsv$evaluated_file_reference
*copyc osv$task_shared_heap
*copyc osv$job_pageable_heap
*copyc pfv$cycle_info_requests
*copyc pfv$file_info_requests
*copyc pfv$null_unique_name
*copyc syv$test_jr_job
*copyc syp$hang_if_job_jrt_set
?? TITLE := 'Global Declarations Declared by This Module', EJECT ??

*copy fmh$path_description_entry

  VAR

{ Place cycle_description_unit at beginning of module to reduce page faults.
{ The size of fmv$initial_cdu_entries should just exceed a page boundary.
{ Initial cycle_description_unit entries.

    fmv$initial_cdu_entries: [XDCL {xdcl'd for test_harness} , oss$job_pageable] array
          [1 .. fmc$number_of_init_cycle_descs] of fmt$cycle_description,

{ Initial global_file_information entries.

    fmv$initial_global_file_entries: [XDCL {xdcl'd for test_harness} , oss$task_shared] array
          [1 .. fmc$number_of_init_cycle_descs] of bat$global_file_information,

{
{  All path table global variables are to be referenced only when the
{  path table is locked.
{

    fmv$path_table_lock: [XDCL, oss$job_pageable] ost$signature_lock := [0],

{
{  The following variables are used for the path table's initial construction.
{

{ Pointer to the initial cycle_description_unit.

    fmv$initial_cdu_pointer: [XDCL, #GATE {gated for BAM$DISPLAY_TABLES & FMM$JOB_RECOVERY} ,
          oss$job_pageable] ^fmt$cycle_description_unit := NIL,

{ Initial cycle_description_unit.

    fmv$initial_cdu: [XDCL {xdcl'd for test_harness} , oss$job_pageable] fmt$cycle_description_unit :=
          [NIL, NIL, 0, NIL, NIL],

{ Initial cycle_description_unit entry_assignment string.

    fmv$init_cdu_entry_assignment: [oss$job_pageable] string (fmc$number_of_init_cycle_descs) :=
          fmc$entry_free,


{ Pointer to the initial path_description_unit.

    fmv$initial_pdu_pointer: [XDCL, #GATE {gated for BAM$DISPLAY_TABLES} ,
          oss$job_pageable] ^fmt$path_description_unit := NIL,

{ Initial path_description_unit.

    fmv$initial_pdu: [XDCL {xdcl'd for test_harness} , oss$job_pageable] fmt$path_description_unit :=
          [NIL, 0, 0, NIL, NIL],

{ Initial path_description_unit entry_assignment string.

    fmv$init_pdu_entry_assignment: [oss$job_pageable] string (fmc$number_of_init_path_descs) :=
          fmc$entry_free,


{
{   The following variables are used for seaching through the path table tree.
{
{ pointer to first entry in first path_description_unit
{ All searched through path table start here

    fmv$path_table_entry_point: [XDCL, #GATE {gated for BAM$DISPLAY_TABLES} ,
          oss$job_pageable] ^fmt$path_description_entry := NIL,

{ Pointer to $LOCAL path_description_entry.

    fmv$local_pde: [oss$job_pageable] ^fmt$path_description_entry := NIL,

{
{  The following variables are used for validating a path handle.
{

    fmv$highest_pdu_offset: [XDCL, #GATE {gated for BAM$DISPLAY_TABLES} , oss$job_pageable]
          ost$segment_offset := 0,

{ Unique counter for path_description_entries.
{ Incremented for each pde assigned in a job.

    fmv$pde_assignment_counter: [XDCL, #GATE {gated for BAM$DISPLAY_TABLES} , oss$job_pageable]
          fmt$pde_assignment_counter := 0,

{
{  The following variables are used for gathering statistics.
{  They are gated for use by bam$display_tables.
{

    fmv$named_objects_created: [XDCL, #GATE, oss$job_pageable] ost$non_negative_integers := 0,
    fmv$named_objects_deleted: [XDCL, #GATE, oss$job_pageable] ost$non_negative_integers := 0,
    fmv$cycle_objects_created: [XDCL, #GATE, oss$job_pageable] ost$non_negative_integers := 0,
    fmv$cycle_objects_deleted: [XDCL, #GATE, oss$job_pageable] ost$non_negative_integers := 0,
    fmv$max_active_objects: [XDCL, #GATE, oss$job_pageable] ost$non_negative_integers := 0,
    fmv$max_path_depth: [XDCL, #GATE, oss$job_pageable] ost$non_negative_integers := 0,
    fmv$path_depth_entries: [XDCL, #GATE, oss$job_pageable] array [1 .. fmc$statistics_max_path_depth] of
          ost$non_negative_integers := [REP fmc$statistics_max_path_depth of 0],

{ Place path_description_unit at end of variable declaration to reduce page faults:
{   1: because the beginning of this table and the preceding variables will be referenced together.
{   2: so that the end of the path table just excess a page boundary, such that following variables
{      will be on their own page.
{ Initial path_description_unit entries.

    fmv$initial_pdu_entries: [XDCL {xdcl'd for test_harness} , oss$job_pageable] array
          [1 .. fmc$number_of_init_path_descs] of fmt$path_description_entry,

{
{  The following variables are used for speed and convenience.
{

    fmv$local_node_name: [READ, oss$job_pageable] fst$path_element := [fsc$local_size, fsc$local],

    fmv$default_detachment_options: [XDCL, #GATE, READ, oss$job_paged_literal] fmt$detachment_options :=
          [rmc$mass_storage_device],

    fmv$default_pde: [READ, oss$job_paged_literal] fmt$path_description_entry := [fmc$pde_unique_identifier, 0
          {cumulative_parental_path_size} , 1 {path_depth} , NIL {entry_assignment} , NIL {pdu_pointer} , 0
          {entry_assignment_counter} , NIL {parental_path_entry} , FALSE {path_handle_name_externalized} ,
          fmc$named_object {entry_type} , NIL {parental_tree_entry} , NIL {right_subtree} ,
          NIL {left_subtree}, [0, osc$null_name] {path_node_name} , 0 {randomized_node_name} , NIL
          {highest_cycle} , NIL {next_cycle_alias_entry} , 0 {active_path_participation_count} ],

    fmv$resolved_file_reference: [READ, oss$job_paged_literal] fst$resolved_file_reference := [
          {path} '',
          {catalog_path_size} 0,
          {complete_path_size} 0,
          {cycle_number} [1, 0],
          {cycle_path_size} 0,
          {family_name} [1, 0],
          {family_path_size} 0,
          {file_name} [1, 0],
          {file_path_size} 0,
          {last_catalog_name} [1, 0],
          {master_catalog_name} [1, 0],
          {master_catalog_path_size} 0,
          {number_of_path_elements} 0,
          {open_position} [1, 0],
          {permanent_file} FALSE],

    initial_catalog_object: [oss$job_paged_literal, READ] fst$goi_object :=
          [fsc$goi_catalog_object, fsc$local, * , NIL, NIL, NIL, NIL, NIL, NIL],

    initial_cycle_object: [oss$job_paged_literal, READ] fst$goi_object :=
          [fsc$goi_cycle_object, 1, * , rmc$mass_storage_device, NIL, NIL, NIL, NIL, FALSE, NIL, NIL],

    initial_file_object: [oss$job_paged_literal, READ] fst$goi_object :=
          [fsc$goi_file_object, * , NIL, NIL, NIL, NIL, osc$null_name, NIL];

  CONST
    fmc$local_offset = 8; { Offset of name size character + $local }


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

*copy fmh$change_recorded_cycle_num

  PROCEDURE [XDCL, #GATE] fmp$change_recorded_cycle_num
    (    evaluated_file_reference: fst$evaluated_file_reference;
         new_cycle: fst$cycle_number;
     VAR status: ost$status);

    VAR
      found: boolean,
      l_evaluated_file_reference: fst$evaluated_file_reference,

{ note: efr must by VAR on call to locate_entry_via_path

      cycle_object: ^fmt$path_description_entry,
      path: fst$path,
      path_size: fst$path_size,
      pde: ^fmt$path_description_entry;

    status.normal := TRUE;
    l_evaluated_file_reference := evaluated_file_reference;

    locate_entry_via_path ($bat$process_pt_work_list [], l_evaluated_file_reference, found, pde, status);

    IF status.normal AND found AND (pde^.entry_type = fmc$file_cycle_object) AND
          (pde^.cycle_number <> new_cycle) THEN
      cycle_object := pde^.parental_path_entry^.highest_cycle;
      locate_cycle (new_cycle, cycle_object);
      IF (cycle_object = NIL) OR (cycle_object^.cycle_description = NIL) THEN
        IF (cycle_object <> NIL) THEN
          extract_cycle_object (cycle_object);
          release_object (cycle_object);
        IFEND;
        extract_cycle_object (pde);
        pde^.cycle_number := new_cycle;
        insert_cycle_object (pde);
      ELSE
        l_evaluated_file_reference.cycle_reference.specification := fsc$cycle_omitted;
        clp$convert_file_ref_to_string (l_evaluated_file_reference, FALSE, path, path_size, status);
        osp$set_status_abnormal (amc$access_method_id, pfe$duplicate_cycle, path (1, path_size), status);
        osp$append_status_integer (osc$status_parameter_delimiter, new_cycle, 10, FALSE, status);
      IFEND;
    IFEND;

  PROCEND fmp$change_recorded_cycle_num;

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

*copy fmh$change_recorded_file_name

  PROCEDURE [XDCL, #GATE] fmp$change_recorded_file_name
    (    evaluated_file_reference: fst$evaluated_file_reference;
         new_file_name: fst$path_element;
     VAR status: ost$status);

    VAR
      found: boolean,
      l_evaluated_file_reference: fst$evaluated_file_reference,

{ note: efr must by VAR on call to locate_entry_via_path

      randomized_node_name: ost$randomized_name,
      cycle_object: ^fmt$path_description_entry,
      new_pde: ^fmt$path_description_entry,
      old_pde: ^fmt$path_description_entry;

    status.normal := TRUE;
    l_evaluated_file_reference := evaluated_file_reference;
    l_evaluated_file_reference.cycle_reference.specification := fsc$cycle_omitted;

    locate_entry_via_path ($bat$process_pt_work_list [], l_evaluated_file_reference, found, old_pde, status);

    IF status.normal AND found AND (old_pde^.path_node_name <> new_file_name) THEN

{ Remove node logically but not physically

      extract_named_object (old_pde);

{ Create a new named object in the path_table by connecting the
{ object extracted above to the proper NIL node located below.
{ Assumption, that permanent files will already have ensured the
{ name is not a duplicate.

{ Locate the position to insert the old_pde with the new_file_name.

      locate_named_object (new_file_name, old_pde^.parental_path_entry, {create=} FALSE, found, new_pde);

      IF found THEN

{ New_file_name is already in the path table.

        cycle_object := new_pde^.highest_cycle;
        get_high_cycle (cycle_object);
        IF cycle_object = NIL THEN

{ New_file_name is not registered, so it can be deleted.

          cycle_object := new_pde^.highest_cycle;

{ Delete all cycle objects.

          WHILE cycle_object <> NIL DO
            extract_cycle_object (cycle_object);
            release_object (cycle_object);
            cycle_object := new_pde^.highest_cycle;
          WHILEND;

{ And then delete the named object.

          extract_named_object (new_pde);
          release_object (new_pde);

{ Locate the position to insert the
{ old_pde with the new_file_name.

          locate_named_object (new_file_name, old_pde^.parental_path_entry, {create=} FALSE, found, new_pde);
        ELSE {cycle_object <> NIL}

{ Reconnect the extracted pde before returning.

          locate_named_object (old_pde^.path_node_name, old_pde^.parental_path_entry, {create=} FALSE, found,
                new_pde);
          IF old_pde^.randomized_node_name < new_pde^.randomized_node_name THEN
            new_pde^.left_subtree := old_pde;
          ELSE
            new_pde^.right_subtree := old_pde;
          IFEND;
          old_pde^.parental_tree_entry := new_pde;
          osp$set_status_abnormal (amc$access_method_id, pfe$name_already_used, new_file_name.value, status);
        IFEND;
      IFEND; {found}

{ Reconnect old_pde to end of search path (new_pde^.)

      IF status.normal THEN
        osp$randomize_name (new_file_name.value, randomized_node_name);
        IF randomized_node_name < new_pde^.randomized_node_name THEN
          new_pde^.left_subtree := old_pde;
        ELSE
          new_pde^.right_subtree := old_pde;
        IFEND;
        old_pde^.parental_tree_entry := new_pde;
        old_pde^.path_node_name := new_file_name;
        old_pde^.randomized_node_name := randomized_node_name;
        cycle_object := old_pde^.highest_cycle;
        WHILE cycle_object <> NIL DO
          cycle_object^.cumulative_parental_path_size := old_pde^.cumulative_parental_path_size +
                new_file_name.size + 1;
          cycle_object := cycle_object^.next_lower_cycle;
        WHILEND;
      IFEND;

    IFEND; {status.normal & found  -  original path}

  PROCEND fmp$change_recorded_file_name;

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

  PROCEDURE [XDCL, #GATE] fmp$complete_pf_object_info
    (    evaluated_file_reference: fst$evaluated_file_reference;
         information_request: fst$goi_information_request;
         password_selector: pft$password_selector;
         validation_ring: ost$valid_ring;
         p_object: ^fst$goi_object;
     VAR p_object_information: ^SEQ ( * );
     VAR all_protected_info_returned: boolean;
     VAR status: ost$status);

    VAR
      found: boolean,
      local_evaluated_file_reference: fst$evaluated_file_reference,
      pde: ^fmt$path_description_entry;

{ The boolean parameter, all_protected_info_returned, is only relevant for
{ password validation.

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

    IF p_object <> NIL THEN
      fmp$lock_path_table (status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;

    /path_table_locked/
      BEGIN
        local_evaluated_file_reference := evaluated_file_reference;
        locate_entry_via_path ($bat$process_pt_work_list [], local_evaluated_file_reference, found, pde,
              status);
        IF NOT status.normal OR NOT found THEN
          EXIT /path_table_locked/; {----->
        IFEND;

{ The pde passed to complete_object must be the parent of the requested object.

        IF pde^.entry_type = fmc$file_cycle_object THEN
          pde := pde^.parental_path_entry;
        IFEND;

        IF p_object^.object_type <> fsc$goi_cycle_object THEN
          pde := pde^.parental_path_entry;
        IFEND;

        complete_object (pde, information_request.object_information_requests, password_selector,
              validation_ring, p_object, all_protected_info_returned, p_object_information, status);
      END /path_table_locked/;

      fmp$unlock_path_table;

    IFEND; {p_object <> NIL}

  PROCEND fmp$complete_pf_object_info;

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

  PROCEDURE [XDCL, #GATE] fmp$create_cycle_description
    (    return_cycle_description: boolean;
     VAR evaluated_file_reference: {i/o} fst$evaluated_file_reference;
     VAR cycle_description_created: boolean;
     VAR cycle_description: ^fmt$cycle_description;
     VAR status: ost$status);

{  fmp$create_cycle_description assumes that if it is called for a permanent file
{  that the evaluate_file_reference is already resolved. If a permanent file is not
{  resolved, a fme$no_cycle_description error will be returned.

    VAR
      found_or_created: boolean,
      pde: ^fmt$path_description_entry;

    cycle_description_created := FALSE;
    cycle_description := NIL;

    fmp$lock_path_table (status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    locate_entry_via_path ($bat$process_pt_work_list [bac$record_path, bac$resolve_path],
          evaluated_file_reference, found_or_created, pde, status);
    IF status.normal AND found_or_created AND (pde^.entry_type = fmc$file_cycle_object) THEN
      IF (pde^.cycle_description = NIL) THEN
        create_cycle_description_entry (pde, pde^.cycle_description, status);
        cycle_description_created := status.normal;
      IFEND;
    ELSEIF status.normal THEN
      osp$set_status_condition (fme$no_cycle_description, status);
    IFEND;

    IF status.normal AND return_cycle_description THEN
      cycle_description := pde^.cycle_description;
    ELSE
      fmp$unlock_path_table;
    IFEND;

  PROCEND fmp$create_cycle_description;

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

*copy fmh$delete_path_description

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

    VAR
      alias_pde: ^fmt$path_description_entry,
      cycle_description: ^fmt$cycle_description,
      cycle_pde: ^fmt$path_description_entry,
      delete_alias: boolean,
      delete_path: boolean,
      detachment_options_record: fmt$detachment_options,
      lock_status: ost$status,
      next_lower_alias: ^fmt$path_description_entry,
      open_count: integer,
      p_tape_descriptor: ^bat$tape_descriptor,
      parent_pde: ^fmt$path_description_entry,
      pde: ^fmt$path_description_entry,
      pf_specified_having_one_alias: boolean,
      save_setfa: boolean,
      system_file_label: fmt$system_file_label,
      temp_static_label: bat$static_label_attributes,
      usage_selections: pft$usage_selections;

    status.normal := TRUE;
    delete_alias := FALSE;
    delete_path := FALSE;
    open_count := 0;
    save_setfa := FALSE;
    pf_specified_having_one_alias := FALSE;

    get_detachment_options (detachment_options, detachment_options_record);

{ only caller is fmp$return_file and it sets fmv$path_table_lock and
{ syp$push_inhibit_job_recovery and clears cycle_description.lock

  /delete/
    BEGIN
      fmp$locate_pde_via_path_handle (evaluated_file_reference.path_handle_info.path_handle, pde, status);
      IF NOT status.normal THEN
        EXIT /delete/; {----->
      IFEND;

      alias_pde := pde;

{ Resolved?

      IF pde^.entry_type = fmc$file_cycle_object THEN

{ Doing implicit detach for close?

        IF implicit_detach THEN

{ Any aliases?

          IF (pde^.first_cycle_alias_entry <> NIL) THEN

{ We do not implicitly detach files which have aliases.

            EXIT /delete/; {----->
          IFEND;
          delete_path := TRUE;

{ More than one alias?

        ELSEIF (pde^.first_cycle_alias_entry <> NIL) AND (pde^.first_cycle_alias_entry^.
              next_cycle_alias_entry <> NIL) THEN

{ Delete the most recent alias

          alias_pde := pde^.first_cycle_alias_entry^.next_cycle_alias_entry;
          WHILE alias_pde^.next_cycle_alias_entry <> NIL DO
            alias_pde := alias_pde^.next_cycle_alias_entry;
          WHILEND;
          delete_alias := TRUE;
        ELSE { 1 or no aliases }

{ delete the only alias if there is one and delete the path

          alias_pde := pde^.first_cycle_alias_entry;
          pf_specified_having_one_alias := (alias_pde <> NIL);
          delete_alias := pf_specified_having_one_alias;
          delete_path := TRUE;
        IFEND;
      ELSE { not resolved }

{ Doing implicit detach for close?

        IF (NOT pde_is_alias (pde)) OR implicit_detach THEN

{ An alias or resolved path must always be passed to
{ fmp$delete_path_description.  All routines that implicitly attach
{ the file must pass a resolved path.

          osp$set_status_abnormal (amc$access_method_id, fme$path_handle_not_resolved,
                'FMP$DELETE_PATH_DESCRIPTION', status);
          EXIT /delete/; {----->
        IFEND;
        pde := pde^.highest_cycle;
        delete_alias := TRUE;
        delete_path := (pde^.first_cycle_alias_entry^.next_cycle_alias_entry = NIL);
      IFEND;

{pde will always be a cycle object here.

      IF pde^.cycle_description <> NIL THEN
        osp$fetch_locked_variable (pde^.cycle_description^.global_file_information^.open_count, open_count);
      IFEND;

      IF delete_path THEN

{ If deleting a path then base DELETED on ability to delete the
{ path and not on the alias.
{ delete the cycle description and global_file_information
{ even if cycle object cannot be deleted

        IF open_count = 0 THEN
          IF pde^.cycle_description <> NIL THEN
            cycle_description := pde^.cycle_description;
            IF cycle_description^.attached_file THEN
              IF (cycle_description^.device_class = rmc$magnetic_tape_device) OR
                    (cycle_description^.device_class = rmc$mass_storage_device) THEN
                IF cycle_description^.permanent_file THEN
                  IF return_permanent_file THEN
                    IF implicit_detach AND (cycle_description^.global_file_information^.
                          implicit_detach_inhibited) THEN
                      EXIT /delete/; {----->
                    IFEND;
                    IF (NOT cycle_description^.system_file_label.file_previously_opened) AND
                          (cycle_description^.static_setfa_entries <> NIL) THEN
                      IF implicit_detach THEN
                        save_setfa := TRUE;
                      ELSE
                        fmp$catalog_set_file_attributes (cycle_description, status);
                      IFEND;
                    IFEND;
                    IF implicit_detach AND (cycle_description^.dynamic_setfa_entries <> NIL) THEN
                      save_setfa := TRUE;
                    IFEND; {setfa check
                    #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
                      IF status.condition = mme$io_write_error THEN
                        fsp$set_evaluated_file_abnormal (evaluated_file_reference,
                              ame$unrecovered_write_error, amc$return_req,
                              'The file should be copied and the original purged before logging out.',
                              status);
                      ELSEIF osp$file_access_condition (status) THEN
                        EXIT /delete/; {----->
                      IFEND;
                    IFEND;
                    syp$hang_if_job_jrt_set (fmc$tjr_return);
                  IFEND;
                ELSE {temporary file}
                  IF (cycle_description^.device_class = rmc$mass_storage_device) AND
                        (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
                      EXIT /delete/; {----->
                    IFEND;
                  IFEND;
                IFEND;
                IF cycle_description^.device_class = rmc$magnetic_tape_device THEN

{ The path table is unlocked here to prevent lock conflicts if an interrupt should occur during dismount.

                  fmp$unlock_path_table;
                  dmp$close_tape_volume (cycle_description^.system_file_id, detachment_options_record,
                        status);
                  fmp$lock_path_table (lock_status);
                  IF NOT status.normal THEN
                    EXIT /delete/; {----->
                  IFEND;
                  IF dmv$initialize_tape_volume.in_progress THEN
                    dmp$setup_tape_init_in_progress ({in_progress} FALSE, {element_name} osc$null_name,
                          {logical_unit} 0);
                  IFEND;
                IFEND;
                IF cycle_description^.job_routing_label <> NIL THEN
                  FREE cycle_description^.job_routing_label IN osv$job_pageable_heap^;
                IFEND;
              ELSEIF cycle_description^.device_class = rmc$terminal_device THEN
                fmp$free_terminal_request (cycle_description);
              IFEND;
              IF cycle_description^.system_file_label.static_label <> NIL THEN
                FREE cycle_description^.system_file_label.static_label IN osv$job_pageable_heap^;
              IFEND;
              cycle_description^.attached_file := FALSE;
            IFEND; {attached_file
            IF cycle_description^.cd_attachment_options <> NIL THEN
              FREE cycle_description^.cd_attachment_options IN osv$job_pageable_heap^;
            IFEND;
            IF save_setfa THEN
              EXIT /delete/; {----->
            IFEND;
            IF cycle_description^.static_setfa_entries <> NIL THEN
              FREE cycle_description^.static_setfa_entries IN osv$job_pageable_heap^;
            IFEND;
            IF cycle_description^.dynamic_setfa_entries <> NIL THEN
              FREE cycle_description^.dynamic_setfa_entries IN osv$job_pageable_heap^;
            IFEND;
            IF cycle_description^.device_class = rmc$magnetic_tape_device THEN
              IF cycle_description^.global_file_information^.device_dependent_info.tape_descriptor <> NIL THEN
                RESET cycle_description^.global_file_information^.device_dependent_info.tape_descriptor;
                NEXT p_tape_descriptor IN cycle_description^.global_file_information^.device_dependent_info.
                      tape_descriptor;
                bap$free_tape_label_sequences ({free_initial_volume_sequence} TRUE, p_tape_descriptor);

                FREE cycle_description^.global_file_information^.device_dependent_info.tape_descriptor IN
                      osv$task_shared_heap^;
              IFEND;
            IFEND;
            cycle_description^.entry_assignment^ := fmc$entry_free;
            pde^.cycle_description := NIL;
          IFEND; {cycle_description <> NIL
          IF delete_alias THEN
            extract_named_object (alias_pde);

{ use actual pointer to alias instead of local_pointer so that
{ the actual pointer is set to NIL by release_object

            release_object (pde^.first_cycle_alias_entry);
          IFEND;
          parent_pde := pde^.parental_path_entry;
          IF NOT pde^.path_handle_name_externalized THEN
            extract_cycle_object (pde);
            release_object (pde);
          IFEND;
          pde := parent_pde;
          WHILE (pde <> NIL) AND (pde^.active_path_participation_count = 0) DO
            parent_pde := pde^.parental_path_entry;
            IF NOT pde^.path_handle_name_externalized THEN
              extract_named_object (pde);
              release_object (pde);
            IFEND;
            pde := parent_pde;
          WHILEND;
          EXIT /delete/; {----->
        ELSE
          IF (NOT delete_alias) AND (NOT implicit_detach) THEN
            fsp$set_evaluated_file_abnormal (evaluated_file_reference, ame$file_not_closed, amc$return_req,
                  ' ', status);
            EXIT /delete/; {----->
          IFEND;
        IFEND;
      IFEND;

      IF delete_alias THEN
        IF NOT (pf_specified_having_one_alias AND (open_count > 0)) THEN

{       Do not delete the alias if a permanent file path was specified,
{       only one alias exists and the file is open.

          IF pde^.first_cycle_alias_entry = alias_pde THEN
            pde^.first_cycle_alias_entry := alias_pde^.next_cycle_alias_entry;
          ELSE

{ find next lower 'older' alias

            next_lower_alias := pde^.first_cycle_alias_entry;

{ Shouldn't have to check for nil since alias_pde must be found

            WHILE next_lower_alias^.next_cycle_alias_entry <> alias_pde DO
              next_lower_alias := next_lower_alias^.next_cycle_alias_entry;
            WHILEND;

{ reconnect remaining aliases

            next_lower_alias^.next_cycle_alias_entry := alias_pde^.next_cycle_alias_entry;
          IFEND;

{ delete the alias

          extract_named_object (alias_pde);
          release_object (alias_pde);
        ELSE
          IF NOT implicit_detach THEN
            fsp$set_evaluated_file_abnormal (evaluated_file_reference, ame$file_not_closed, amc$return_req,
                  ' ', status);
          IFEND;
          EXIT /delete/; {----->
        IFEND;
      IFEND;

    END /delete/;

  PROCEND fmp$delete_path_description;

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

{ PURPOSE:
{   The purpose of this procedure is to get the requested information about a
{   $local catalog, file, or cycle.

  PROCEDURE [XDCL, #GATE] fmp$get_$local_object_info
    (    evaluated_file_reference: fst$evaluated_file_reference;
         information_request: fst$goi_information_request;
         password_selector: pft$password_selector;
         validation_ring: ost$valid_ring;
         p_object_info: {output^} ^fst$goi_object_information;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      found_or_created: boolean,
      local_evaluated_file_reference: fst$evaluated_file_reference,
      p_object: ^fst$goi_object,
      path: fst$path,
      path_node_name: fst$path_element,
      path_size: fst$path_size,
      path_status: ost$status,
      pde: ^fmt$path_description_entry,
      password_validated: boolean;

?? NEWTITLE := 'store_resolved_path', EJECT ??

    PROCEDURE [INLINE] store_resolved_path;

      NEXT p_object_info^.resolved_path: [path_size] IN p_object_information;
      IF p_object_info^.resolved_path = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN; {----->
      IFEND;
      p_object_info^.resolved_path^ := path (1, path_size);

    PROCEND store_resolved_path;

?? OLDTITLE, EJECT ??

    path_status.normal := TRUE;

    fmp$lock_path_table (status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

  /path_table_locked/
    BEGIN
      IF evaluated_file_reference.number_of_path_elements = 1 THEN
        path := ':' CAT fsc$local;
        path_size := fsc$local_size + 1;
        IF information_request.object_information_requests = $fst$goi_object_info_requests [] THEN
          EXIT /path_table_locked/; {----->
        IFEND;

        IF (password_selector.password_specified = pfc$specific_password_option) AND
              (password_selector.password <> osc$null_name) THEN
          osp$set_status_condition (pfe$catalogs_have_no_password, status);
          EXIT /path_table_locked/; {----->
        IFEND;

        NEXT p_object IN p_object_information;
        IF p_object = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          EXIT /path_table_locked/; {----->
        IFEND;

        get_$local_catalog_object_info (information_request.object_information_requests, validation_ring,
              p_object, p_object_information, status);

      ELSEIF information_request.object_information_requests * pfv$file_info_requests <>
            $fst$goi_object_info_requests [] THEN
        path_node_name.size := $INTEGER (evaluated_file_reference.path_structure (fmc$local_offset));
        path_node_name.value := evaluated_file_reference.path_structure
              (fmc$local_offset + 1, path_node_name.size);
        locate_named_object (path_node_name, fmv$local_pde, {create =} FALSE, found_or_created, pde);
        IF (NOT found_or_created) OR (pde^.highest_cycle = NIL) THEN
          bap$set_evaluated_file_abnormal (evaluated_file_reference, ame$file_not_known,
                'PFP$GET_OBJECT_INFORMATION', '', status);
          fmp$unlock_path_table;
          RETURN; {----->
        IFEND;

        NEXT p_object IN p_object_information;
        IF p_object = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          EXIT /path_table_locked/; {----->
        IFEND;

        IF (password_selector.password_specified = pfc$specific_password_option) AND
              (password_selector.password <> osc$null_name) THEN
          osp$set_status_condition (fse$local_files_have_no_pw, status);
          osp$append_status_file (osc$status_parameter_delimiter, path (1, path_size), status);
          password_validated := FALSE;
        ELSE
          password_validated := TRUE;
        IFEND;

        get_$local_file_object_info (evaluated_file_reference.cycle_reference,
              information_request.object_information_requests, validation_ring, password_validated, p_object,
              pde, p_object_information, status);

        recreate_path_string (pde, path, path_size, path_status);

      ELSEIF information_request.object_information_requests * pfv$cycle_info_requests <>
            $fst$goi_object_info_requests [] THEN
        local_evaluated_file_reference := evaluated_file_reference;
        locate_entry_via_path ($bat$process_pt_work_list [bac$resolve_path], local_evaluated_file_reference,
              found_or_created, pde, status);
        IF (NOT status.normal) OR (NOT found_or_created) OR (pde^.cycle_description = NIL) THEN
          bap$set_evaluated_file_abnormal (local_evaluated_file_reference, ame$file_not_known,
                'PFP$GET_OBJECT_INFORMATION', '', status);
          fmp$unlock_path_table;
          RETURN; {----->
        IFEND;

        NEXT p_object IN p_object_information;
        IF p_object = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          EXIT /path_table_locked/; {----->
        IFEND;

        IF (password_selector.password_specified = pfc$specific_password_option) AND
              (password_selector.password <> osc$null_name) THEN
          osp$set_status_condition (fse$local_files_have_no_pw, status);
          osp$append_status_file (osc$status_parameter_delimiter, path (1, path_size), status);
          password_validated := FALSE;
        ELSE
          password_validated := TRUE;
        IFEND;

        get_$local_cycle_object_info (pde, information_request.object_information_requests, validation_ring,
              password_validated, p_object, p_object_information, status);

        recreate_path_string (pde, path, path_size, path_status);

      ELSE
        p_object := NIL;
        clp$convert_file_ref_to_string (evaluated_file_reference, {include_open_position =} FALSE, path,
              path_size, path_status);
      IFEND;

      IF status.normal THEN
        p_object_info^.object := p_object;
      ELSEIF status.condition = ame$ring_validation_error THEN
        p_object_info^.object := p_object;
        osp$append_status_file (osc$status_parameter_delimiter, path (1, path_size), status);
        osp$append_status_parameter (osc$status_parameter_delimiter, 'PFP$GET_OBJECT_INFORMATION', status);
      IFEND;
    END /path_table_locked/;

    IF path_status.normal THEN
      store_resolved_path;
    ELSEIF status.normal THEN
      status := path_status;
    IFEND;

    fmp$unlock_path_table;

  PROCEND fmp$get_$local_object_info;

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

  PROCEDURE [XDCL, #GATE] fmp$get_list_of_$local_files
    (VAR info: pft$p_info;
     VAR status: ost$status);

    VAR
      outer_record_type: ^pft$info_record_type,
      outer_record_size: ^pft$info_record_body_size,
      directory: pft$p_directory_array,
      directory_record_type: ^pft$info_record_type,
      directory_record_size: ^pft$info_record_body_size,
      directory_entry: pft$p_directory_array_entry,
      info_record: pft$p_info_record,
      cycle_object: ^fmt$path_description_entry,
      pdu: ^fmt$path_description_unit,
      pde: ^fmt$path_description_entry,
      saved_info: pft$p_info,
      entry: integer,
      entry_count: integer;

    saved_info := info;
    NEXT outer_record_type IN info;
    outer_record_type^ := pfc$multi_item_info_record;
    NEXT outer_record_size IN info;
    NEXT directory_record_type IN info;
    directory_record_type^ := pfc$directory_array_record;
    NEXT directory_record_size IN info;
    entry_count := 0;

    fmp$lock_path_table (status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

  /get_list_of_$local/
    BEGIN

{ Get pointer to the first entry in the first path_description_unit.

      IF fmv$initial_pdu_pointer <> NIL THEN
        pdu := fmv$initial_pdu_pointer;
      ELSE
        EXIT /get_list_of_$local/; {----->
      IFEND;

      WHILE pdu <> NIL DO

{ Look at every assigned entry in a path_description_unit.

        FOR entry := 1 TO #SIZE (pdu^.entry_assignment^) DO
          IF pdu^.entry_assignment^ (entry) = fmc$entry_assigned THEN
            pde := ^pdu^.entries^ [entry];
            IF (pde^.entry_type = fmc$named_object)
{         } AND (pde^.parental_path_entry <> NIL)
{         } AND (pde^.parental_path_entry^.path_node_name.value = fsc$local) THEN
              cycle_object := pde^.highest_cycle;
              get_high_cycle (cycle_object);
              IF (cycle_object <> NIL) AND cycle_object^.cycle_description^.attached_file THEN
                NEXT directory_entry IN info;
                directory_entry^.name := pde^.path_node_name.value;
                directory_entry^.name_type := pfc$file_name;
                directory_entry^.info_offset := 0;
                entry_count := entry_count + 1;
              IFEND;
            IFEND;
          IFEND;
        FOREND;

{ move on to next unit if pointer is not NIL

        pdu := pdu^.next_path_description_unit;
      WHILEND;
    END /get_list_of_$local/;

    fmp$unlock_path_table;

    directory_record_size^ := #SIZE (pft$directory_array_entry) * entry_count;
    outer_record_size^ := #SIZE (pft$info_record_type) + #SIZE (pft$info_record_body_size) +
          directory_record_size^;

    info := saved_info;
    pfp$find_next_info_record (info, info_record, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;
    pfp$find_directory_array (info_record, directory, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    sort_directory (directory);

  PROCEND fmp$get_list_of_$local_files;

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

{*copy fmh$get_path_elements

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

    VAR
      pde: ^fmt$path_description_entry;

    evaluated_file_reference := fsv$evaluated_file_reference;

    fmp$lock_path_table (status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

  /get_elements/
    BEGIN
      fmp$locate_pde_via_path_handle (path_handle, pde, status);
      IF NOT status.normal THEN
        EXIT /get_elements/; {----->
      IFEND;

      evaluated_file_reference.path_handle_info.path_handle := path_handle;
      evaluated_file_reference.path_handle_info.path_handle_present := TRUE;

      IF pde_is_alias (pde) THEN
        pde := pde^.highest_cycle;

{ Change path_handle to match the path being returned.

        evaluated_file_reference.path_handle_info.path_handle.segment_offset := #OFFSET (pde);
        evaluated_file_reference.path_handle_info.path_handle.assignment_counter :=
              pde^.entry_assignment_counter;
      IFEND;

      recreate_path_elements (pde, evaluated_file_reference);
    END /get_elements/;

    fmp$unlock_path_table;

  PROCEND fmp$get_path_elements;

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

  PROCEDURE [XDCL, #GATE] fmp$get_path_string
    (    path_handle: fmt$path_handle;
         lock_path_table: boolean;
     VAR path: fst$path;
     VAR path_size: fst$path_size;
     VAR status: ost$status);

    VAR
      pde: ^fmt$path_description_entry;

    status.normal := TRUE;
    path := '';
    path_size := 0;

    IF lock_path_table THEN
      fmp$lock_path_table (status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;
    IFEND;

  /get_string/
    BEGIN
      fmp$locate_pde_via_path_handle (path_handle, pde, status);
      IF NOT status.normal THEN
        EXIT /get_string/; {----->
      IFEND;

      IF pde_is_alias (pde) THEN
        pde := pde^.highest_cycle;
      IFEND;

      recreate_path_string (pde, path, path_size, status);
    END /get_string/;

    IF lock_path_table THEN
      fmp$unlock_path_table;
    IFEND;

  PROCEND fmp$get_path_string;

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

  PROCEDURE [XDCL, #GATE] fmp$get_resolved_file_reference
    (VAR evaluated_file_reference: {i/o} fst$evaluated_file_reference;
     VAR resolved_file_reference: fst$resolved_file_reference;
     VAR status: ost$status);

    CONST
      get_resolved_file_reference = 'FMP$GET_RESOLVED_FILE_REFERENCE';

    VAR
      cycle_string: ost$string,
      found_or_created: boolean,
      last_catalog_pde: ^fmt$path_description_entry,
      master_catalog_pde: ^fmt$path_description_entry,
      pde: ^fmt$path_description_entry;

    resolved_file_reference := fmv$resolved_file_reference;

    fmp$lock_path_table (status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

  /path_table_locked/
    BEGIN
      locate_entry_via_path ($bat$process_pt_work_list [bac$record_path, bac$resolve_path,
            bac$resolve_to_catalog], evaluated_file_reference, found_or_created, pde, status);
      IF NOT status.normal THEN
        EXIT /path_table_locked/; {----->
      ELSEIF NOT found_or_created THEN
        IF (evaluated_file_reference.number_of_path_elements = 1) AND
              (fsp$path_element (^evaluated_file_reference, 1) ^ = fsc$local) THEN
          osp$set_status_abnormal (amc$access_method_id, pfe$name_not_permanent_file,
                fsp$path_element (^evaluated_file_reference, 1) ^, status);
          EXIT /path_table_locked/; {----->
        ELSE
          osp$set_status_abnormal (amc$access_method_id, fme$system_error,
                '- NOT found_or_created in ' CAT get_resolved_file_reference, status);
          EXIT /path_table_locked/; {----->
        IFEND;
      IFEND;

{ Note: path depth is the same in last element and it's cycle objects

      resolved_file_reference.number_of_path_elements := pde^.path_depth;

      IF pde^.entry_type = fmc$file_cycle_object THEN
        clp$convert_integer_to_string (pde^.cycle_number, 10, FALSE, cycle_string, status);
        IF NOT status.normal THEN
          EXIT /path_table_locked/; {----->
        IFEND;

        IF (pde^.cumulative_parental_path_size + cycle_string.size + 1) > fsc$max_path_size THEN
          osp$set_status_abnormal (amc$access_method_id, cle$file_reference_too_long,
                get_resolved_file_reference, status);
          EXIT /path_table_locked/; {----->
        IFEND;

        resolved_file_reference.file_path_size := pde^.cumulative_parental_path_size;
        resolved_file_reference.cycle_path_size := resolved_file_reference.file_path_size +
              cycle_string.size + 1;

{ The following code builds the resolved file reference starting
{ from the cycle_number and works its way back to the family_name.
{ The open_position, if specified, is appended after the path has been built.

{ Cycle_number

        resolved_file_reference.cycle_number.index := resolved_file_reference.file_path_size + 2;
        resolved_file_reference.cycle_number.size := cycle_string.size;
        resolved_file_reference.path (resolved_file_reference.cycle_number.index,
              resolved_file_reference.cycle_number.size) := cycle_string.
              value (1, resolved_file_reference.cycle_number.size);

        pde := pde^.parental_path_entry;
        IF (pde = NIL) OR (pde^.parental_path_entry = NIL) THEN
          osp$set_status_abnormal (amc$access_method_id, fme$system_error,
                '- path too short in ' CAT get_resolved_file_reference, status);
          EXIT /path_table_locked/; {----->
        IFEND;

        resolved_file_reference.catalog_path_size := pde^.cumulative_parental_path_size;

{ Delimiter

        resolved_file_reference.path (resolved_file_reference.file_path_size + 1, 1) := '.';

{ File name

        resolved_file_reference.file_name.index := resolved_file_reference.catalog_path_size + 2;
        resolved_file_reference.file_name.size := pde^.path_node_name.size;
        resolved_file_reference.path (resolved_file_reference.file_name.index,
              resolved_file_reference.file_name.size) := pde^.path_node_name.value;

        pde := pde^.parental_path_entry;

{ Delimiter

        resolved_file_reference.path (resolved_file_reference.catalog_path_size + 1, 1) := '.';
      ELSEIF (evaluated_file_reference.path_resolution = fsc$catalog_path) THEN
        resolved_file_reference.catalog_path_size := pde^.cumulative_parental_path_size +
              pde^.path_node_name.size + 1;
        resolved_file_reference.cycle_path_size := resolved_file_reference.catalog_path_size;
        resolved_file_reference.file_path_size := resolved_file_reference.catalog_path_size;
      ELSE
        osp$set_status_abnormal (amc$access_method_id, fme$system_error,
              '- path not resolved in ' CAT get_resolved_file_reference, status);
        EXIT /path_table_locked/; {----->
      IFEND;

{ Last catalog name

      resolved_file_reference.last_catalog_name.index := pde^.cumulative_parental_path_size + 2;
      resolved_file_reference.last_catalog_name.size := pde^.path_node_name.size;
      resolved_file_reference.path (resolved_file_reference.last_catalog_name.index,
            resolved_file_reference.last_catalog_name.size) := pde^.path_node_name.value;

{ All remaining catalog names

      last_catalog_pde := pde;
      master_catalog_pde := last_catalog_pde;
      WHILE pde^.parental_path_entry <> NIL DO
        master_catalog_pde := pde;
        resolved_file_reference.path (pde^.cumulative_parental_path_size + 1, 1) := '.';
        pde := pde^.parental_path_entry;
        resolved_file_reference.path (pde^.cumulative_parental_path_size + 2, pde^.path_node_name.size) :=
              pde^.path_node_name.value;
      WHILEND;
      resolved_file_reference.path (1, 1) := ':';

      resolved_file_reference.permanent_file := (pde^.path_node_name.value (1,
            pde^.path_node_name.size) <> fsc$local);

{ Master & Family catalog names

      IF resolved_file_reference.permanent_file THEN
        IF (pde <> master_catalog_pde) THEN
          IF master_catalog_pde = last_catalog_pde THEN
            resolved_file_reference.master_catalog_name := resolved_file_reference.last_catalog_name;
            resolved_file_reference.master_catalog_path_size := resolved_file_reference.catalog_path_size;
          ELSE
            resolved_file_reference.master_catalog_name.size := master_catalog_pde^.path_node_name.size;
            resolved_file_reference.master_catalog_name.index :=
                  master_catalog_pde^.cumulative_parental_path_size + 2;
            resolved_file_reference.master_catalog_path_size :=
                  master_catalog_pde^.cumulative_parental_path_size +
                  resolved_file_reference.master_catalog_name.size + 1;
          IFEND;
        ELSE
          resolved_file_reference.master_catalog_path_size := pde^.path_node_name.size + 1;
        IFEND;
        resolved_file_reference.family_name.size := pde^.path_node_name.size;
        resolved_file_reference.family_name.index := 2;
        resolved_file_reference.family_path_size := resolved_file_reference.family_name.size + 1;
      ELSE
        IF (master_catalog_pde <> last_catalog_pde) OR (pde <> master_catalog_pde) THEN
          osp$set_status_abnormal (amc$access_method_id, fme$system_error,
                '- local path too long in ' CAT get_resolved_file_reference, status);
          EXIT /path_table_locked/; {----->
        IFEND;
        resolved_file_reference.master_catalog_name := resolved_file_reference.last_catalog_name;
        resolved_file_reference.master_catalog_path_size := resolved_file_reference.catalog_path_size;
        resolved_file_reference.family_name := resolved_file_reference.master_catalog_name;
        resolved_file_reference.family_path_size := resolved_file_reference.master_catalog_path_size;
      IFEND;

{ Open_position

      IF evaluated_file_reference.path_handle_info.path_handle.open_position.specified AND
            (evaluated_file_reference.path_resolution <> fsc$catalog_path) THEN
        resolved_file_reference.open_position.size := clv$open_position_designator
              [evaluated_file_reference.path_handle_info.path_handle.open_position.value].size;
        IF resolved_file_reference.cycle_path_size + resolved_file_reference.open_position.size + 1 >
              fsc$max_path_size THEN
          osp$set_status_abnormal (amc$access_method_id, cle$file_reference_too_long,
                get_resolved_file_reference, status);
          EXIT /path_table_locked/; {----->
        IFEND;
        resolved_file_reference.open_position.index := resolved_file_reference.cycle_path_size + 2;
        resolved_file_reference.path (resolved_file_reference.cycle_path_size + 1, 1) := '.';
        resolved_file_reference.path (resolved_file_reference.open_position.index,
              resolved_file_reference.open_position.size) := clv$open_position_designator [
              evaluated_file_reference.path_handle_info.path_handle.open_position.value].
              value (1, resolved_file_reference.open_position.size);
        resolved_file_reference.complete_path_size := resolved_file_reference.cycle_path_size +
              resolved_file_reference.open_position.size + 1;
      ELSE
        resolved_file_reference.complete_path_size := resolved_file_reference.cycle_path_size;
      IFEND;

    END /path_table_locked/;

    fmp$unlock_path_table;

  PROCEND fmp$get_resolved_file_reference;

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

  PROCEDURE [XDCL] fmp$get_setfa_values_for_object
    (    evaluated_file_reference: fst$evaluated_file_reference;
         information_request: fst$goi_information_request;
         validation_ring: ost$valid_ring;
         p_object: ^fst$goi_object;
     VAR p_object_information: ^SEQ ( * );
     VAR setfa_values_found: boolean;
     VAR status: ost$status);

    VAR
      all_protected_info_returned: boolean,
      cycle_pde: ^fmt$path_description_entry,
      found: boolean,
      local_evaluated_file_reference: fst$evaluated_file_reference,
      password_selector: pft$password_selector,
      pde: ^fmt$path_description_entry;

    status.normal := TRUE;

    IF p_object <> NIL THEN
      fmp$lock_path_table (status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;

    /path_table_locked/
      BEGIN
        local_evaluated_file_reference := evaluated_file_reference;
        locate_entry_via_path ($bat$process_pt_work_list [], local_evaluated_file_reference, found, pde,
              status);
        IF NOT status.normal OR NOT found THEN
          setfa_values_found := FALSE;
          EXIT /path_table_locked/; {----->
        IFEND;

        IF pde^.entry_type = fmc$named_object THEN
          cycle_pde := pde^.highest_cycle;
          get_high_cycle (cycle_pde);
        ELSE
          cycle_pde := pde;
        IFEND;

        setfa_values_found := (cycle_pde <> NIL) AND (cycle_pde^.cycle_description <> NIL) AND
              ((cycle_pde^.cycle_description^.static_setfa_entries <> NIL) OR
              (cycle_pde^.cycle_description^.dynamic_setfa_entries <> NIL));
        IF NOT setfa_values_found THEN
          EXIT /path_table_locked/; {----->
        IFEND;

        initialize_cycle_object (p_object);
        p_object^.cycle_number := cycle_pde^.cycle_number;
        pde := cycle_pde^.parental_path_entry;

        all_protected_info_returned := TRUE;

{ The value of password_selector is irrelevant in this case since a validation
{ error could not have occurred.

        complete_object (pde, information_request.object_information_requests, password_selector,
              validation_ring, p_object, all_protected_info_returned, p_object_information, status);
        setfa_values_found := status.normal;
      END /path_table_locked/;

      fmp$unlock_path_table;
    IFEND; {p_object <> NIL}

  PROCEND fmp$get_setfa_values_for_object;

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

  PROCEDURE [XDCL, #GATE] fmp$initialize_path_table;

{ This must be the first procedure called that references the path_table
{ during job initialization.
{ This procedure will initialize the first path_description_entry of the first
{ path_description_unit to $LOCAL.  This procedure will also initialize all
{ job specific pointers to the first path_description_unit.
{ This procedure is called by JMP$JOB_BEGIN.

    VAR
      local_catalog_path_handle: fmt$path_handle;

{ Initialize the first path_description_unit pointers and statistics.

    fmv$initial_pdu.entry_assignment := ^fmv$init_pdu_entry_assignment;
    fmv$initial_pdu.entries := ^fmv$initial_pdu_entries;
    fmv$highest_pdu_offset := #OFFSET (fmv$initial_pdu.entries) +
          (#SIZE (fmt$path_description_entry) * (fmc$number_of_init_path_descs - 1)) + 1;
    fmv$initial_pdu_pointer := ^fmv$initial_pdu;
    fmv$path_table_entry_point := ^fmv$initial_pdu_entries [1];

{ Assign the first path_description_entry to $LOCAL.

    increment_assignment_counter;
    fmv$initial_pdu.entry_assignment^ (1) := fmc$entry_assigned;
    fmv$initial_pdu.total_count := 1;
    fmv$initial_pdu.current_count := 1;
    fmv$named_objects_created := 1;
    fmv$max_active_objects := 1;

{ Initialize job pointer to the $LOCAL path_description_entry.

    fmv$local_pde := fmv$path_table_entry_point;

{ Initialize the $LOCAL path_description_entry.

    fmv$local_pde^.unique_identifier := fmc$pde_unique_identifier;
    fmv$local_pde^.cumulative_parental_path_size := 0;
    fmv$local_pde^.path_depth := 1;
    fmv$local_pde^.entry_assignment := ^fmv$initial_pdu.entry_assignment^ (1, 1);
    fmv$local_pde^.pdu_pointer := ^fmv$initial_pdu;
    fmv$local_pde^.entry_assignment_counter := fmv$pde_assignment_counter;
    fmv$local_pde^.parental_path_entry := NIL;
    fmv$local_pde^.path_handle_name_externalized := TRUE; { Don't ever let $LOCAL be deleted }
    fmv$local_pde^.entry_type := fmc$named_object;
    fmv$local_pde^.parental_tree_entry := NIL;
    fmv$local_pde^.left_subtree := NIL;
    fmv$local_pde^.right_subtree := NIL;
    fmv$local_pde^.path_node_name := fmv$local_node_name;
    osp$randomize_name (fmv$local_node_name.value, fmv$local_pde^.randomized_node_name);
    fmv$local_pde^.highest_cycle := NIL;
    fmv$local_pde^.next_cycle_alias_entry := NIL;
    fmv$local_pde^.active_path_participation_count := 0;

{ set up path handle name for $local

    local_catalog_path_handle.segment_offset := #OFFSET (fmv$local_pde);
    local_catalog_path_handle.assignment_counter := fmv$local_pde^.entry_assignment_counter;
    local_catalog_path_handle.open_position.specified := FALSE;
    clp$construct_path_handle_name (local_catalog_path_handle, clv$local_catalog_handle_name);

{ Initialize first cycle description

    fmv$initial_cdu.global_file_entries_pointer := ^fmv$initial_global_file_entries;
    fmv$initial_cdu.entry_assignment := ^fmv$init_cdu_entry_assignment;
    fmv$initial_cdu.entries := ^fmv$initial_cdu_entries;
    fmv$initial_cdu_pointer := ^fmv$initial_cdu;

  PROCEND fmp$initialize_path_table;

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

*copy fmh$is_file_attached

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

    VAR
      pde: ^fmt$path_description_entry;

    attached := FALSE;
    fmp$lock_path_table (status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    fmp$locate_pde_via_path_handle (path_handle, pde, status);
    IF status.normal THEN
      IF pde^.entry_type = fmc$file_cycle_object THEN
        attached := (pde^.cycle_description <> NIL) AND pde^.cycle_description^.attached_file;
      IFEND;
    IFEND;

    fmp$unlock_path_table;

  PROCEND fmp$is_file_attached;

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

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

    VAR
      pde: ^fmt$path_description_entry;

    attached := FALSE;
    fmp$lock_path_table (status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    fmp$locate_pde_via_path_handle (path_handle, pde, status);
    IF status.normal THEN
      IF pde^.entry_type = fmc$file_cycle_object THEN
        attached := pde^.cycle_description <> NIL;
      IFEND;
    IFEND;

    fmp$unlock_path_table;

  PROCEND fmp$is_file_registered;

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

*copy fmh$locate_cd_via_path_handle

  PROCEDURE [XDCL, #GATE] fmp$locate_cd_via_path_handle
    (    path_handle: fmt$path_handle;
         lock_path_table: boolean;
     VAR cycle_description: ^fmt$cycle_description;
     VAR status: ost$status);

    VAR
      pde: ^fmt$path_description_entry;

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

    IF lock_path_table THEN
      fmp$lock_path_table (status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;
    IFEND;

    fmp$locate_pde_via_path_handle (path_handle, pde, status);
    IF status.normal THEN
      IF pde^.entry_type = fmc$file_cycle_object THEN
        IF (pde^.cycle_description <> NIL) THEN
          cycle_description := pde^.cycle_description;
        IFEND;
      ELSEIF pde_is_alias (pde) THEN
        IF (pde^.highest_cycle^.cycle_description <> NIL) THEN
          cycle_description := pde^.highest_cycle^.cycle_description;
        IFEND;
      IFEND;
    IFEND;

    IF cycle_description = NIL THEN
      osp$set_status_condition (fme$no_cycle_description, status);
      IF lock_path_table THEN
        fmp$unlock_path_table;
      IFEND;
    IFEND;

  PROCEND fmp$locate_cd_via_path_handle;

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

  PROCEDURE [XDCL] fmp$locate_cycle_description
    (VAR evaluated_file_reference: {i/o} fst$evaluated_file_reference;
     VAR cycle_description: ^fmt$cycle_description;
     VAR status: ost$status);

    VAR
      found: boolean,
      pde: ^fmt$path_description_entry;

    cycle_description := NIL;
    fmp$lock_path_table (status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    locate_entry_via_path ($bat$process_pt_work_list [bac$resolve_path, bac$resolve_to_catalog],
          evaluated_file_reference, found, pde, status);
    IF status.normal AND found AND (pde^.entry_type = fmc$file_cycle_object) AND
          (pde^.cycle_description <> NIL) THEN
      cycle_description := pde^.cycle_description;
      RETURN; {The path table should remain locked because the cycle description is being returned.
    ELSEIF status.normal OR (status.condition = pfe$unknown_permanent_file) THEN
      osp$set_status_condition (fme$no_cycle_description, status);
    IFEND;

    fmp$unlock_path_table;

  PROCEND fmp$locate_cycle_description;

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

  PROCEDURE [XDCL, #GATE] fmp$process_pt_request
    (    process_pt_work_list: bat$process_pt_work_list;
         local_file_name: amt$local_file_name;
     VAR evaluated_file_reference: fst$evaluated_file_reference;
     VAR cycle_description: ^fmt$cycle_description;
     VAR process_pt_results: bat$process_pt_results;
     VAR status: ost$status);

?? NEWTITLE := 'PROCEDURE assign_alias_to_file', EJECT ??

    PROCEDURE assign_alias_to_file
      (    local_file_name: amt$local_file_name;
           path_pde: {i/o} ^fmt$path_description_entry;
       VAR status: ost$status);

      VAR
        alias_found_or_created: boolean,
        alias_path_node_name: fst$path_element,
        alias_pde: ^fmt$path_description_entry,
        cycle_object: ^fmt$path_description_entry,
        temp_alias_pde: ^fmt$path_description_entry,
        temp_path_handle: fmt$path_handle;

      IF (path_pde = NIL) OR (path_pde^.entry_type <> fmc$file_cycle_object) THEN
        osp$set_status_abnormal (amc$access_method_id, fme$system_error,
              'Entry not a cycle_object in fmp$process_pt_request', status);
        RETURN; {----->
      IFEND;

{ Record the local_file_name as ':$local.local_file_name'

      alias_path_node_name.value := local_file_name;
      alias_path_node_name.size := clp$trimmed_string_size (local_file_name);
      locate_named_object (alias_path_node_name, fmv$local_pde, {create=} TRUE, alias_found_or_created,
            alias_pde);

{ Check for pfe$lfn_in_use

      IF alias_pde^.highest_cycle <> NIL THEN
        cycle_object := alias_pde^.highest_cycle;
        get_high_cycle (cycle_object);
        IF cycle_object = NIL THEN
          cycle_object := alias_pde^.highest_cycle;

{ Delete all cycle objects.

          WHILE cycle_object <> NIL DO
            extract_cycle_object (cycle_object);
            release_object (cycle_object);
            cycle_object := alias_pde^.highest_cycle;
          WHILEND;
        ELSE
          osp$set_status_abnormal (amc$access_method_id, pfe$lfn_in_use, local_file_name, status);

{ Note: path_resolution is already set to fsc$unresolved_path

          RETURN; {----->
        IFEND;
      IFEND;

{ Link alias to the path's cycle_object.

      alias_pde^.highest_cycle := path_pde;
      alias_pde^.next_cycle_alias_entry := NIL;
      IF path_pde^.first_cycle_alias_entry = NIL THEN
        path_pde^.first_cycle_alias_entry := alias_pde;
      ELSE

{ Reconstruct pointers between alias_pde's from first to last.
{ Set temp_alias_pde to the first_alias.

        temp_alias_pde := path_pde^.first_cycle_alias_entry;
        WHILE temp_alias_pde^.next_cycle_alias_entry <> NIL DO
          temp_alias_pde := temp_alias_pde^.next_cycle_alias_entry;
        WHILEND;
        temp_alias_pde^.next_cycle_alias_entry := alias_pde;
      IFEND;

    PROCEND assign_alias_to_file;
?? OLDTITLE ??

    VAR
      found_or_created: boolean,
      pde: ^fmt$path_description_entry;

    status.normal := TRUE;
    cycle_description := NIL;
    IF bac$resolve_path IN process_pt_work_list THEN
      evaluated_file_reference.path_resolution := fsc$unresolved_path;
    IFEND;
    process_pt_results := $bat$process_pt_results [];

    IF NOT (bac$inhibit_locking_pt IN process_pt_work_list) THEN
      fmp$lock_path_table (status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;
    IFEND;

  /path_table_locked/
    BEGIN

{ Record path.

      locate_entry_via_path (process_pt_work_list, evaluated_file_reference, found_or_created, pde, status);
      IF (NOT status.normal) OR (NOT found_or_created) THEN
        EXIT /path_table_locked/; {----->
      IFEND;

      IF (bac$externalize_path_handle IN process_pt_work_list) AND
            (NOT pde^.path_handle_name_externalized) THEN
        pde^.path_handle_name_externalized := TRUE;
      IFEND;

      IF local_file_name <> osc$null_name THEN
        assign_alias_to_file (local_file_name, pde, status);
        IF NOT status.normal THEN
          EXIT /path_table_locked/; {----->
        IFEND;
      IFEND;

{ Return/create cycle description.

      IF pde^.entry_type = fmc$file_cycle_object THEN
        IF pde^.cycle_description = NIL THEN
          IF bac$create_cycle_description IN process_pt_work_list THEN
            create_cycle_description_entry (pde, pde^.cycle_description, status);
            IF NOT status.normal THEN
              EXIT /path_table_locked/; {----->
            IFEND;
            process_pt_results := process_pt_results + $bat$process_pt_results
                  [bac$cycle_description_created, bac$cycle_description_exists];
          IFEND;
        ELSE
          process_pt_results := process_pt_results + $bat$process_pt_results [bac$cycle_description_exists];
        IFEND;
        IF bac$return_cycle_description IN process_pt_work_list THEN
          cycle_description := pde^.cycle_description;
        IFEND;
      IFEND;

    END /path_table_locked/;

    IF (cycle_description = NIL) AND (NOT (bac$inhibit_locking_pt IN process_pt_work_list)) THEN
      fmp$unlock_path_table;
    IFEND;

  PROCEND fmp$process_pt_request;

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

  PROCEDURE [XDCL] fmp$setup_job_environment_info
    (    cycle_description_p: {input^} ^fmt$cycle_description;
         path_handle_p: ^fmt$path_handle;
         job_environment_information_p: {output^} ^fst$job_environment_information;
     VAR object_information_p: ^SEQ ( * ));

    VAR
      access_mode: fst$file_access_option,
      cd_attachment_options: ^fmt$cd_attachment_options,
      dynamic_setfa_entries: ^fst$setfa_attachment_options,
      density: rmt$density,
      local_object_information_p: ^SEQ ( * ),
      local_status: ost$status,
      object_info_p: ^fst$goi_object_information,
      removable_media_group: ost$name,
      subject_path_handle_name: fst$path_handle_name;


    job_environment_information_p^ := fsv$default_job_environ_info;

    IF cycle_description_p^.attached_file THEN
      #UNCHECKED_CONVERSION (cycle_description_p^.system_file_label.descriptive_label.global_access_mode,
            job_environment_information_p^.attached_access_modes);
      #UNCHECKED_CONVERSION (cycle_description_p^.system_file_label.descriptive_label.global_share_mode,
            job_environment_information_p^.attached_share_modes);
      IF cycle_description_p^.device_class = rmc$magnetic_tape_device THEN
        fmp$get_attached_tape_info (cycle_description_p^.system_file_id,
              job_environment_information_p^.volume_list, job_environment_information_p^.volume_number,
              job_environment_information_p^.volume_overflow_allowed, density, removable_media_group,
              object_information_p, local_status);
      IFEND;
    IFEND;

    cd_attachment_options := cycle_description_p^.cd_attachment_options;
    IF (cd_attachment_options <> NIL) THEN
      IF cd_attachment_options^.free_behind_specified THEN
        job_environment_information_p^.mass_storage_free_behind := cd_attachment_options^.free_behind;
        job_environment_information_p^.specified_attachment_options :=
              job_environment_information_p^.specified_attachment_options +
              $fst$specified_attach_options [fsc$free_behind_ao];
      IFEND;
      IF cd_attachment_options^.job_write_concurrency_specified THEN
        job_environment_information_p^.job_write_concurrency := cd_attachment_options^.job_write_concurrency;
        job_environment_information_p^.specified_attachment_options :=
              job_environment_information_p^.specified_attachment_options +
              $fst$specified_attach_options [fsc$job_write_concurrency_ao];
      IFEND;
      IF cd_attachment_options^.sequential_access_specified THEN
        job_environment_information_p^.mass_storage_sequential_access :=
              cd_attachment_options^.sequential_access;
        job_environment_information_p^.specified_attachment_options :=
              job_environment_information_p^.specified_attachment_options +
              $fst$specified_attach_options [fsc$sequential_access_ao];
      IFEND;
      IF cd_attachment_options^.transfer_size_specified THEN
        job_environment_information_p^.transfer_size := cd_attachment_options^.transfer_size;
        job_environment_information_p^.specified_attachment_options :=
              job_environment_information_p^.specified_attachment_options +
              $fst$specified_attach_options [fsc$transfer_size_ao];
      IFEND;
      IF (cd_attachment_options^.private_read_specified) THEN
        job_environment_information_p^.private_read.specified_on_attach := TRUE;
        job_environment_information_p^.private_read.value := cd_attachment_options^.private_read;
      IFEND;
    IFEND;

    job_environment_information_p^.concurrent_open_count :=
          cycle_description_p^.global_file_information^.open_count;

    IF path_handle_p <> NIL THEN
      clp$construct_path_handle_name (path_handle_p^, subject_path_handle_name);
      fmp$get_list_of_connected_files (subject_path_handle_name,
            job_environment_information_p^.connected_files, object_information_p);
    IFEND;

    job_environment_information_p^.cycle_attached := cycle_description_p^.attached_file;
    job_environment_information_p^.job_file_address := cycle_description_p^.global_file_information^.
          positioning_info.record_info.current_byte_address;
    job_environment_information_p^.job_file_position := cycle_description_p^.global_file_information^.
          positioning_info.record_info.file_position;

    FOR access_mode := LOWERVALUE (fst$file_access_option) TO UPPERVALUE (fst$file_access_option) DO
      IF cycle_description_p^.global_file_information^.prevented_open_access_modes [access_mode] <> 0 THEN
        job_environment_information_p^.prevented_open_access_modes :=
              job_environment_information_p^.prevented_open_access_modes +
              $fst$file_access_options [access_mode];
      IFEND;
    FOREND;

    dynamic_setfa_entries := cycle_description_p^.dynamic_setfa_entries;
    IF dynamic_setfa_entries <> NIL THEN
      IF dynamic_setfa_entries^.access_modes_specified THEN
        job_environment_information_p^.setfa_access_modes := dynamic_setfa_entries^.access_modes;
        job_environment_information_p^.attachment_options_sources.access_modes_source := amc$file_command;
      IFEND;

      IF dynamic_setfa_entries^.error_exit_name_specified THEN
        job_environment_information_p^.error_exit_procedure_name := dynamic_setfa_entries^.error_exit_name;
        job_environment_information_p^.attachment_options_sources.error_exit_name_source := amc$file_command;
      IFEND;
      IF dynamic_setfa_entries^.error_limit_specified THEN
        job_environment_information_p^.error_limit := dynamic_setfa_entries^.error_limit;
        job_environment_information_p^.attachment_options_sources.error_limit_source := amc$file_command;
      IFEND;
      IF dynamic_setfa_entries^.label_exit_name_specified THEN
        job_environment_information_p^.label_exit_procedure_name := dynamic_setfa_entries^.label_exit_name;
        job_environment_information_p^.attachment_options_sources.label_exit_name_source := amc$file_command;
      IFEND;
      IF dynamic_setfa_entries^.message_control_specified THEN
        job_environment_information_p^.message_control := dynamic_setfa_entries^.message_control;
        job_environment_information_p^.attachment_options_sources.message_control_source := amc$file_command;
      IFEND;
      IF cycle_description_p^.path_handle.open_position.specified THEN
        job_environment_information_p^.open_position := cycle_description_p^.path_handle.open_position.value;
        job_environment_information_p^.attachment_options_sources.open_position_source := amc$file_reference;
      ELSEIF dynamic_setfa_entries^.open_position_specified THEN
        job_environment_information_p^.open_position := dynamic_setfa_entries^.open_position;
        job_environment_information_p^.attachment_options_sources.open_position_source := amc$file_command;
      IFEND;
    IFEND;

  PROCEND fmp$setup_job_environment_info;

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

  PROCEDURE [XDCL, #GATE] fmp$unlock_path_table_at_tskend;

    VAR
      lock_status: ost$signature_lock_status;

    osp$test_sig_lock (fmv$path_table_lock, lock_status);
    IF lock_status = osc$sls_locked_by_current_task THEN
      fmp$unlock_path_table;
      osp$recoverable_system_error ('FMV$PATH_TABLE_LOCK is already set by the current task.', NIL);
    IFEND;

  PROCEND fmp$unlock_path_table_at_tskend;

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

  PROCEDURE allocate_cycle_description_unit
    (VAR {input,output} cdu: ^fmt$cycle_description_unit);

{ PURPOSE: This procedure will allocate a cycle_description_unit,
{          initialize its entry_assignment string, and links it to
{          the previous cycle_description_unit.

    VAR
      entries_seq: ^SEQ ( * ),
      old_cdu: ^fmt$cycle_description_unit;

    old_cdu := cdu;

    ALLOCATE entries_seq: [[REP 1 OF fmt$cycle_description_unit, REP fmc$cycle_table_allocation_size OF char,
          REP fmc$cycle_table_allocation_size OF fmt$cycle_description]] IN osv$job_pageable_heap^;

    RESET entries_seq;
    NEXT cdu IN entries_seq;
    IF cdu = NIL THEN
      osp$system_error ('NEXT of cdu resulted in NIL', NIL);
    IFEND;
    NEXT cdu^.entry_assignment: [fmc$cycle_table_allocation_size] IN entries_seq;
    IF cdu^.entry_assignment = NIL THEN
      osp$system_error ('NEXT of cdu^.entry_assignment resulted in NIL', NIL);
    IFEND;
    NEXT cdu^.entries: [1 .. fmc$cycle_table_allocation_size] IN entries_seq;
    IF cdu^.entries = NIL THEN
      osp$system_error ('NEXT of cdu^.entries resulted in NIL on entries', NIL);
    IFEND;

    ALLOCATE cdu^.global_file_entries_pointer: [1 .. fmc$cycle_table_allocation_size] IN
          osv$task_shared_heap^;

    old_cdu^.next_cycle_description_unit := cdu;
    cdu^.next_cycle_description_unit := NIL;
    cdu^.total_count := 0;

{ CYBIL will blank fill a string, so the following assignment is ok
{ as long as fmc$entry_free is a blank.

    cdu^.entry_assignment^ := fmc$entry_free;

  PROCEND allocate_cycle_description_unit;

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

  PROCEDURE allocate_path_description_unit
    (VAR {input,output} pdu: ^fmt$path_description_unit);

{ Purpose: This procedure is used to allocate another unit of
{          path_description_entries if the existing ones have no more
{          unassigned entries.  A pointer to the new pdu is returned.

    VAR
      entries_seq: ^SEQ ( * ),
      new_highest_pdu_offset: ost$segment_offset,
      old_pdu: ^fmt$path_description_unit;

    old_pdu := pdu;

    ALLOCATE entries_seq: [[REP 1 OF fmt$path_description_unit, REP fmc$path_table_allocation_size OF char,
          REP fmc$path_table_allocation_size OF fmt$path_description_entry]] IN osv$job_pageable_heap^;

    RESET entries_seq;
    NEXT pdu IN entries_seq;
    IF pdu = NIL THEN
      osp$system_error ('NEXT of pdu resulted in NIL', NIL);
    IFEND;
    NEXT pdu^.entry_assignment: [fmc$path_table_allocation_size] IN entries_seq;
    IF pdu^.entry_assignment = NIL THEN
      osp$system_error ('NEXT of pdu^.entry_assignment resulted in NIL', NIL);
    IFEND;
    NEXT pdu^.entries: [1 .. fmc$path_table_allocation_size] IN entries_seq;
    IF pdu^.entries = NIL THEN
      osp$system_error ('NEXT of pdu^.entries resulted in NIL', NIL);
    IFEND;

    old_pdu^.next_path_description_unit := pdu;

    pdu^.total_count := 0;
    pdu^.current_count := 0;
    pdu^.next_path_description_unit := NIL;

{ CYBIL will blank fill a string, so the following assignment is ok
{ as long as fmc$entry_free is a blank.

    pdu^.entry_assignment^ := fmc$entry_free;


{ update statistics

    new_highest_pdu_offset := #OFFSET (pdu^.entries) + (#SIZE (fmt$path_description_entry) *
          (fmc$path_table_allocation_size - 1)) + 1;
    IF new_highest_pdu_offset > fmv$highest_pdu_offset THEN
      fmv$highest_pdu_offset := new_highest_pdu_offset;
    IFEND;

  PROCEND allocate_path_description_unit;

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

  PROCEDURE complete_object
    (    pde: ^fmt$path_description_entry;
         object_info_requests: fst$goi_object_info_requests;
         password_selector: pft$password_selector;
         validation_ring: ost$valid_ring;
         p_object: ^fst$goi_object;
     VAR all_protected_info_returned: boolean;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      current_pde: ^fmt$path_description_entry,
      found: boolean,
      header: ^fmt$static_label_header,
      label_size: ost$non_negative_integers,
      local_status: ost$status,
      object_list_index: ost$positive_integers,
      path: fst$path,
      path_node_name: fst$path_element,
      path_size: fst$path_size;

    all_protected_info_returned := TRUE;

    CASE p_object^.object_type OF
    = fsc$goi_catalog_object =
      IF p_object^.subcatalog_and_file_object_list <> NIL THEN
        path_node_name.value := p_object^.catalog_name;
        path_node_name.size := clp$trimmed_string_size (p_object^.catalog_name);
        locate_named_object (path_node_name, pde, {create =} FALSE, found, current_pde);
        IF found THEN
          FOR object_list_index := 1 TO UPPERBOUND (p_object^.subcatalog_and_file_object_list^) DO
            complete_object (current_pde, object_info_requests, password_selector, validation_ring,
                  ^p_object^.subcatalog_and_file_object_list^ [object_list_index],
                  all_protected_info_returned, p_object_information, status);
            IF NOT status.normal THEN
              RETURN; {----->
            IFEND;
          FOREND;
        IFEND;
      IFEND;

    = fsc$goi_file_object =
      IF p_object^.cycle_object_list <> NIL THEN
        path_node_name.value := p_object^.file_name;
        path_node_name.size := clp$trimmed_string_size (p_object^.file_name);
        locate_named_object (path_node_name, pde, {create =} FALSE, found, current_pde);
        IF found THEN
          FOR object_list_index := 1 TO UPPERBOUND (p_object^.cycle_object_list^) DO
            complete_object (current_pde, object_info_requests, password_selector, validation_ring,
                  ^p_object^.cycle_object_list^ [object_list_index], all_protected_info_returned,
                  p_object_information, status);
            IF NOT status.normal THEN
              RETURN; {----->
            IFEND;
          FOREND;
        IFEND;
      IFEND;

    = fsc$goi_cycle_object =
      current_pde := pde^.highest_cycle;
      locate_cycle (p_object^.cycle_number, current_pde);
      IF (current_pde <> NIL) AND (current_pde^.cycle_description <> NIL) THEN
        IF (fsc$goi_cycle_size IN object_info_requests) AND current_pde^.cycle_description^.
              attached_file AND (current_pde^.cycle_description^.device_class = rmc$mass_storage_device) AND
              current_pde^.cycle_description^.permanent_file AND
              ($fst$file_access_options [fsc$append, fsc$shorten, fsc$modify] *
              current_pde^.cycle_description^.attached_access_modes <> $fst$file_access_options []) AND
              current_pde^.cycle_description^.global_file_information^.eoi_set THEN
          IF p_object^.cycle_size = NIL THEN
            NEXT p_object^.cycle_size IN p_object_information;
            IF p_object^.cycle_size = NIL THEN
              osp$set_status_condition (pfe$info_full, status);
              RETURN; {----->
            IFEND;
          IFEND;
          p_object^.cycle_size^ := current_pde^.cycle_description^.global_file_information^.eoi_byte_address;
        IFEND;
        IF (fsc$goi_file_label IN object_info_requests) OR (fsc$goi_job_environment_info IN
              object_info_requests) THEN
          IF p_object^.validation_error THEN
            IF current_pde^.cycle_description^.attached_file THEN
              IF (password_selector.password_specified = pfc$default_password_option) THEN
                IF current_pde^.cycle_description^.system_file_label.file_previously_opened THEN
                  validate_ring_access (validation_ring, current_pde^.cycle_description^.system_file_label.
                        static_label, status);
                  IF NOT status.normal THEN
                    all_protected_info_returned := FALSE;
                    RETURN; {----->
                  ELSE
                    p_object^.validation_error := FALSE;
                  IFEND;
                ELSE
                  p_object^.validation_error := FALSE;
                IFEND;
              ELSE
                all_protected_info_returned := FALSE;
                RETURN; {----->
              IFEND;
            ELSE
              all_protected_info_returned := FALSE;
            IFEND;
          IFEND;

          IF all_protected_info_returned AND (fsc$goi_file_label IN object_info_requests) THEN
            IF current_pde^.cycle_description^.static_setfa_entries = NIL THEN
              IF current_pde^.cycle_description^.attached_file THEN
                IF current_pde^.cycle_description^.system_file_label.static_label = NIL THEN
                  label_size := #SIZE (fmt$static_label_header);
                  NEXT p_object^.file_label: [[REP label_size OF cell]] IN p_object_information;
                  IF p_object^.file_label = NIL THEN
                    osp$set_status_condition (pfe$info_full, status);
                    RETURN; {----->
                  IFEND;
                  i#move (^fmv$static_label_header, p_object^.file_label, label_size);
                  IF NOT current_pde^.cycle_description^.system_file_label.file_previously_opened THEN
                    RESET p_object^.file_label;
                    NEXT header IN p_object^.file_label;
                    header^.file_previously_opened := FALSE;
                  IFEND;
                ELSE
                  label_size := #SIZE (current_pde^.cycle_description^.system_file_label.static_label^);
                  NEXT p_object^.file_label: [[REP label_size OF cell]] IN p_object_information;
                  IF p_object^.file_label = NIL THEN
                    osp$set_status_condition (pfe$info_full, status);
                    RETURN; {----->
                  IFEND;
                  i#move (current_pde^.cycle_description^.system_file_label.static_label,
                        p_object^.file_label, label_size);
                IFEND;
              IFEND; { attached_file }
            ELSE { preserved_attribute were specified on a SETFA }
              IF (current_pde^.cycle_description^.attached_file AND
                    NOT current_pde^.cycle_description^.system_file_label.file_previously_opened AND
                    (current_pde^.cycle_description^.system_file_label.static_label = NIL)) OR
                    (NOT current_pde^.cycle_description^.attached_file AND (p_object^.file_label = NIL)) THEN
                label_size := #SIZE (current_pde^.cycle_description^.static_setfa_entries^);
                NEXT p_object^.file_label: [[REP label_size OF cell]] IN p_object_information;
                IF p_object^.file_label = NIL THEN
                  osp$set_status_condition (pfe$info_full, status);
                  RETURN; {----->
                IFEND;
                i#move (current_pde^.cycle_description^.static_setfa_entries, p_object^.file_label,
                      label_size);
              ELSE
                IF current_pde^.cycle_description^.attached_file AND
                      (current_pde^.cycle_description^.system_file_label.static_label <> NIL) THEN
                  IF current_pde^.cycle_description^.system_file_label.file_previously_opened THEN
                    label_size := #SIZE (current_pde^.cycle_description^.system_file_label.static_label^);
                    NEXT p_object^.file_label: [[REP label_size OF cell]] IN p_object_information;
                    IF p_object^.file_label = NIL THEN
                      osp$set_status_condition (pfe$info_full, status);
                      RETURN; {----->
                    IFEND;
                    i#move (current_pde^.cycle_description^.system_file_label.static_label,
                          p_object^.file_label, label_size);
                  ELSE
                    p_object^.file_label := current_pde^.cycle_description^.system_file_label.static_label;
                  IFEND;
                IFEND;
                fmp$merge_setfa_entries (current_pde^.cycle_description^.static_setfa_entries, p_object,
                      p_object_information, status);
                IF NOT status.normal THEN
                  p_object^.file_label := NIL;
                  RETURN; {----->
                IFEND;
              IFEND;
            IFEND; { static_setfa_entries = NIL }
          IFEND; { file_label requested }

          IF (fsc$goi_job_environment_info IN object_info_requests) THEN
            IF (current_pde^.cycle_description^.dynamic_setfa_entries <> NIL) OR
                  all_protected_info_returned THEN
              IF current_pde^.cycle_description^.attached_file THEN
                validate_ring_access (validation_ring, current_pde^.cycle_description^.system_file_label.
                      static_label, status);
              ELSE
                validate_default_ring_access (validation_ring, status);
              IFEND;
              IF NOT status.normal THEN
                RETURN; {----->
              IFEND;
              NEXT p_object^.job_environment_information IN p_object_information;
              IF p_object^.job_environment_information = NIL THEN
                osp$set_status_condition (pfe$info_full, status);
              ELSE
                fmp$setup_job_environment_info (current_pde^.cycle_description, {path_handle_p} NIL,
                      p_object^.job_environment_information, p_object_information);
              IFEND;
            IFEND;
          IFEND;

        IFEND; {file_label or job_environment_info requested}
      ELSE
        all_protected_info_returned := FALSE;
      IFEND;

    ELSE
    CASEND;

  PROCEND complete_object;

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

  PROCEDURE create_cycle_description_entry
    (    pde: ^fmt$path_description_entry;
     VAR cycle_description: ^fmt$cycle_description;
     VAR status: ost$status);

{ PURPOSE: This procedure searches the already allocated
{          cycle_description_units in order starting with the first to
{          have been allocated until it finds a free entry.  If no
{          free entries are found then another cycle_description_unit
{          will be allocated.  The entry found will be initialized.

    VAR
      cdu: ^fmt$cycle_description_unit,
      found: boolean,
      validated_name: amt$local_file_name,
      valid_name: boolean,
      index: 1 .. cyc$max_string_size + 1;

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

    IF pdes_first_element_is_$local (pde) THEN

{ Validate a temporary file name before creating a cycle_description
{ for it to ensure an invalid name is not used for an actual file.

      clp$validate_new_file_name (pde^.parental_path_entry^.path_node_name.value, validated_name, valid_name);
      IF NOT valid_name THEN
        osp$set_status_abnormal (amc$access_method_id, pfe$bad_permanent_file_name, validated_name, status);
        RETURN; {----->
      IFEND;
    IFEND;

    cdu := fmv$initial_cdu_pointer;

{ Always start search from first cycle_description_unit and
{ search all units before allocating more.

    WHILE cycle_description = NIL DO
      #SCAN (fmv$entry_free_selector, cdu^.entry_assignment^, index, found);
      IF found THEN
        cdu^.total_count := cdu^.total_count + 1;
        cdu^.entry_assignment^ (index) := fmc$entry_assigned;
        cycle_description := ^cdu^.entries^ [index];
        cycle_description^.entry_assignment := ^cdu^.entry_assignment^ (index, 1);
        cycle_description^.path_handle.segment_offset := #OFFSET (pde);
        cycle_description^.path_handle.assignment_counter := pde^.entry_assignment_counter;
        cycle_description^.path_handle.open_position.specified := FALSE;
        cycle_description^.global_file_information := ^cdu^.global_file_entries_pointer^ [index];
        cycle_description^.global_file_information^ := fmv$global_file_information;
        cycle_description^.static_setfa_entries := NIL;
        cycle_description^.dynamic_setfa_entries := NIL;
        cycle_description^.cd_attachment_options := NIL;
        cycle_description^.attached_file := FALSE;
      ELSEIF cdu^.next_cycle_description_unit <> NIL THEN
        cdu := cdu^.next_cycle_description_unit;
      ELSE
        allocate_cycle_description_unit (cdu);
      IFEND;
    WHILEND;

  PROCEND create_cycle_description_entry;

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

  PROCEDURE [INLINE] create_cycle_object
    (    cycle_number: fst$cycle_number;
         parent_path_node: ^fmt$path_description_entry;
     VAR cycle_object: ^fmt$path_description_entry);

{ PURPOSE: Search assignment strings in allocated pdu's in order for an
{          unassigned entry.  Initializes the entry once found.

    VAR
      active_objects: ost$non_negative_integers,
      index: 1 .. cyc$max_string_size + 1,
      pdu: ^fmt$path_description_unit,
      found: boolean;

    found := FALSE;

    cycle_object := NIL;

{ Start at the root of path_table.
{ Note: It is not possible for the incoming PDU to be NIL since at least
{   one named_object must always be created first.

    pdu := fmv$initial_pdu_pointer;

{ Search assignment strings in order for an unassigned entry.

    REPEAT

{ The pdu should probably be locked for scan and until entry assigned.

      IF pdu^.current_count < #SIZE (pdu^.entry_assignment^) THEN
        #SCAN (fmv$entry_free_selector, pdu^.entry_assignment^, index, found);
      ELSE
        found := FALSE;
      IFEND;
      IF found THEN
        increment_assignment_counter;
        pdu^.entry_assignment^ (index) := fmc$entry_assigned;
        pdu^.total_count := pdu^.total_count + 1;
        pdu^.current_count := pdu^.current_count + 1;
        fmv$cycle_objects_created := fmv$cycle_objects_created + 1;
        active_objects := fmv$cycle_objects_created + fmv$named_objects_created - fmv$cycle_objects_deleted -
              fmv$named_objects_deleted;
        IF active_objects > fmv$max_active_objects THEN
          fmv$max_active_objects := active_objects;
        IFEND;
        cycle_object := ^pdu^.entries^ [index];

{ Initialize the cycle_object.

        cycle_object^.unique_identifier := fmc$pde_unique_identifier;
        cycle_object^.cumulative_parental_path_size := parent_path_node^.cumulative_parental_path_size +
              parent_path_node^.path_node_name.size + 1; { +1 is for period }
        cycle_object^.path_depth := parent_path_node^.path_depth;
        cycle_object^.entry_assignment := ^pdu^.entry_assignment^ (index, 1);
        cycle_object^.pdu_pointer := pdu;
        cycle_object^.entry_assignment_counter := fmv$pde_assignment_counter;
        cycle_object^.parental_path_entry := parent_path_node;
        cycle_object^.path_handle_name_externalized := FALSE;
        cycle_object^.entry_type := fmc$file_cycle_object;
        cycle_object^.cycle_number := cycle_number;
        cycle_object^.first_cycle_alias_entry := NIL;
        cycle_object^.cycle_description := NIL;
        cycle_object^.parental_path_entry^.active_path_participation_count :=
              cycle_object^.parental_path_entry^.active_path_participation_count + 1;
        insert_cycle_object (cycle_object);

      ELSEIF pdu^.next_path_description_unit <> NIL THEN
        pdu := pdu^.next_path_description_unit;

      ELSE
        allocate_path_description_unit (pdu);
      IFEND;
    UNTIL cycle_object <> NIL;

  PROCEND create_cycle_object;

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

  PROCEDURE [INLINE] create_named_object
    (    parent_path_node: ^fmt$path_description_entry;
         parent_tree_node: ^fmt$path_description_entry;
         path_node_name: fst$path_element;
         randomized_node_name: ost$randomized_name;
     VAR node: ^fmt$path_description_entry);

{ PURPOSE: Search assignment strings in allocated pdu's in order for an
{          unassigned entry.  Initialize the entry once found.

    VAR
      active_objects: ost$non_negative_integers,
      index: 1 .. cyc$max_string_size + 1,
      pdu: ^fmt$path_description_unit,
      found: boolean;

    found := FALSE;
    node := NIL;
    pdu := fmv$initial_pdu_pointer;

    REPEAT

{ The pdu should probably be locked for scan and until entry assigned.

      IF pdu^.current_count < #SIZE (pdu^.entry_assignment^) THEN
        #SCAN (fmv$entry_free_selector, pdu^.entry_assignment^, index, found);
      ELSE
        found := FALSE;
      IFEND;
      IF found THEN
        increment_assignment_counter;
        pdu^.entry_assignment^ (index) := fmc$entry_assigned;
        pdu^.total_count := pdu^.total_count + 1;
        pdu^.current_count := pdu^.current_count + 1;
        fmv$named_objects_created := fmv$named_objects_created + 1;
        active_objects := fmv$cycle_objects_created + fmv$named_objects_created - fmv$cycle_objects_deleted -
              fmv$named_objects_deleted;
        IF active_objects > fmv$max_active_objects THEN
          fmv$max_active_objects := active_objects;
        IFEND;
        node := ^pdu^.entries^ [index];

{ Initialize the node.

        node^.active_path_participation_count := 0;
        node^.unique_identifier := fmc$pde_unique_identifier;
        IF parent_path_node <> NIL THEN
          node^.cumulative_parental_path_size := parent_path_node^.cumulative_parental_path_size +
                parent_path_node^.path_node_name.size + 1;

{ +1 is for period, or colon

          node^.path_depth := parent_path_node^.path_depth + 1;
          parent_path_node^.active_path_participation_count :=
                parent_path_node^.active_path_participation_count + 1;
        ELSE { If no parent then it must be first element in path }
          node^.cumulative_parental_path_size := 0;
          node^.path_depth := 1;
        IFEND;
        node^.entry_assignment := ^pdu^.entry_assignment^ (index, 1);
        node^.pdu_pointer := pdu;
        node^.entry_assignment_counter := fmv$pde_assignment_counter;
        node^.parental_path_entry := parent_path_node;
        node^.path_handle_name_externalized := FALSE;
        node^.entry_type := fmc$named_object;
        node^.parental_tree_entry := parent_tree_node;
        node^.left_subtree := NIL;
        node^.right_subtree := NIL;
        node^.path_node_name := path_node_name;
        node^.randomized_node_name := randomized_node_name;
        node^.highest_cycle := NIL;
        node^.next_cycle_alias_entry := NIL;
        IF parent_tree_node <> NIL THEN

{ Connect parental_tree_entry to the new subtree entry

          IF randomized_node_name < parent_tree_node^.randomized_node_name THEN
            node^.parental_tree_entry^.left_subtree := node;
          ELSE
            node^.parental_tree_entry^.right_subtree := node;
          IFEND;
        IFEND;
      ELSEIF pdu^.next_path_description_unit <> NIL THEN
        pdu := pdu^.next_path_description_unit;
      ELSE
        allocate_path_description_unit (pdu);
      IFEND;
    UNTIL node <> NIL;

  PROCEND create_named_object;

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

  PROCEDURE [INLINE] extract_cycle_object
    (VAR cycle_object: ^fmt$path_description_entry);

{ PURPOSE: This procedure extracts a cycle_object from a linked list
{          of cycle_objects.  The named_object is updated to reflect
{          the removal.


    IF cycle_object = cycle_object^.parental_path_entry^.highest_cycle THEN
      cycle_object^.parental_path_entry^.highest_cycle := cycle_object^.next_lower_cycle;
    IFEND;

    IF cycle_object^.next_lower_cycle <> NIL THEN
      cycle_object^.next_lower_cycle^.next_higher_cycle := cycle_object^.next_higher_cycle;
    IFEND;

    IF cycle_object^.next_higher_cycle <> NIL THEN
      cycle_object^.next_higher_cycle^.next_lower_cycle := cycle_object^.next_lower_cycle;
    IFEND;

  PROCEND extract_cycle_object;

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

  PROCEDURE [INLINE] extract_named_object
    (    pde: ^fmt$path_description_entry);

{ PURPOSE: This procedure uncouples a named_object entry from the binary
{          tree and re-constructs the tree without it.  The named_object
{          entry is left intact, just uncoupled.

    VAR
      parent_pde: ^fmt$path_description_entry,
      right_pde: ^fmt$path_description_entry,
      left_pde: ^fmt$path_description_entry,
      temp_pde: ^fmt$path_description_entry;

    left_pde := pde^.left_subtree;
    right_pde := pde^.right_subtree;
    parent_pde := pde^.parental_tree_entry;

  /extract/
    BEGIN

{ Determine if there are no descendants

      IF (left_pde = NIL) AND (right_pde = NIL) THEN
        IF parent_pde <> NIL THEN
          IF parent_pde^.left_subtree = pde THEN
            parent_pde^.left_subtree := NIL;
          ELSE
            parent_pde^.right_subtree := NIL;
          IFEND;
        IFEND;
        EXIT /extract/; {----->
      IFEND;

{ Determine if there is more than one descendants

      IF (left_pde <> NIL) AND (right_pde <> NIL) THEN
        temp_pde := left_pde;

{ Find rightmost node with NIL right_subtree pointer below left subtree
{ of node to be deleted.

        WHILE temp_pde^.right_subtree <> NIL DO
          temp_pde := temp_pde^.right_subtree;
        WHILEND;

        IF parent_pde <> NIL THEN

{ Hook left_pde to parent.

          IF parent_pde^.left_subtree = pde THEN
            parent_pde^.left_subtree := left_pde;
          ELSE
            parent_pde^.right_subtree := left_pde;
          IFEND;
        IFEND;
        left_pde^.parental_tree_entry := parent_pde;

{ Hook right bottom node of left_pde to right_pde.

        right_pde^.parental_tree_entry := temp_pde;
        temp_pde^.right_subtree := right_pde;

        EXIT /extract/; {----->
      IFEND;

{ Only one descendant.

      IF left_pde <> NIL THEN
        IF parent_pde <> NIL THEN

{ Hook left_pde to parent.

          IF parent_pde^.left_subtree = pde THEN
            parent_pde^.left_subtree := left_pde;
          ELSE
            parent_pde^.right_subtree := left_pde;
          IFEND;
        IFEND;
        left_pde^.parental_tree_entry := parent_pde;
      ELSE { right_pde <> NIL }
        IF parent_pde <> NIL THEN

{ Hook right_pde to parent.

          IF parent_pde^.right_subtree = pde THEN
            parent_pde^.right_subtree := right_pde;
          ELSE
            parent_pde^.left_subtree := right_pde;
          IFEND;
        IFEND;
        right_pde^.parental_tree_entry := parent_pde;
      IFEND;

    END /extract/;

    pde^.parental_tree_entry := NIL;
    pde^.left_subtree := NIL;
    pde^.right_subtree := NIL;

  PROCEND extract_named_object;

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

  PROCEDURE [INLINE] get_detachment_options
    (    detachment_options: ^fst$detachment_options;
     VAR detachment_options_record: fmt$detachment_options);

    VAR
      detachment_option_index: integer;

    detachment_options_record.device_class := rmc$mass_storage_device;
    IF detachment_options <> NIL THEN
      FOR detachment_option_index := 1 TO UPPERBOUND (detachment_options^) DO
        CASE detachment_options^ [detachment_option_index].selector OF
        = fsc$do_unload_volume =
          detachment_options_record.device_class := rmc$magnetic_tape_device;
          detachment_options_record.physical_unload := detachment_options^ [detachment_option_index].
                unload_volume;
        = fsc$do_null_detachment_option =
          ;
        ELSE
        CASEND;
      FOREND;
    IFEND;
  PROCEND get_detachment_options;

?? TITLE := 'PROCEDURE get_$local_catalog_object_info', EJECT ??

  PROCEDURE get_$local_catalog_object_info
    (    object_information_requests: fst$goi_object_info_requests;
         validation_ring: ost$valid_ring;
         p_object: {output^} ^fst$goi_object;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      cycle_pde: ^fmt$path_description_entry,
      cycle_reference: fst$cycle_reference,
      file_count: ost$non_negative_integers,
      file_index: ost$positive_integers,
      pde: ^fmt$path_description_entry,
      pdu: ^fmt$path_description_unit,
      pdu_entry: integer;

    status.normal := TRUE;

    p_object^ := initial_catalog_object;

{ Get the requested information for every file in the $LOCAL catalog, except aliases.
    IF (fsc$goi_file_object_list IN object_information_requests) AND (fmv$initial_pdu_pointer <> NIL) THEN
      pdu := fmv$initial_pdu_pointer;
      file_count := 0;
      WHILE pdu <> NIL DO
        FOR pdu_entry := 1 TO #SIZE (pdu^.entry_assignment^) DO
          IF pdu^.entry_assignment^ (pdu_entry) = fmc$entry_assigned THEN
            pde := ^pdu^.entries^ [pdu_entry];

{ Calculate the number of temporary files in order to know how much space to allocate for the
{ file_object_list array.

            IF (pde^.entry_type = fmc$named_object) AND (pde^.parental_path_entry = fmv$local_pde) AND
                  (pde^.highest_cycle <> NIL) AND (NOT pde_is_alias (pde)) THEN
              cycle_pde := pde^.highest_cycle;
              get_high_cycle (cycle_pde);
              IF cycle_pde <> NIL THEN
                file_count := file_count + 1;
              IFEND;
            IFEND;
          IFEND;
        FOREND;
        pdu := pdu^.next_path_description_unit;
      WHILEND;

      NEXT p_object^.subcatalog_and_file_object_list: [1 .. file_count] IN p_object_information;
      pdu := fmv$initial_pdu_pointer;
      file_index := 1;
      WHILE (pdu <> NIL) AND (file_index <= file_count) DO
        FOR pdu_entry := 1 TO #SIZE (pdu^.entry_assignment^) DO
          IF pdu^.entry_assignment^ (pdu_entry) = fmc$entry_assigned THEN
            pde := ^pdu^.entries^ [pdu_entry];
            IF (pde^.entry_type = fmc$named_object) AND (pde^.parental_path_entry = fmv$local_pde)
{         } AND (pde^.highest_cycle <> NIL) AND (NOT pde_is_alias (pde)) THEN
              cycle_pde := pde^.highest_cycle;
              get_high_cycle (cycle_pde);
              IF cycle_pde <> NIL THEN
                cycle_reference.specification := fsc$high_cycle;
                get_$local_file_object_info (cycle_reference, object_information_requests, validation_ring,
                      {password_validated =} TRUE, ^p_object^.subcatalog_and_file_object_list^ [file_index],
                      pde, p_object_information, status);
                file_index := file_index + 1;
              IFEND;
            IFEND;
          IFEND;
        FOREND;
        pdu := pdu^.next_path_description_unit;
      WHILEND;
    IFEND;

  PROCEND get_$local_catalog_object_info;

?? TITLE := 'PROCEDURE get_$local_cycle_object_info', EJECT ??

  PROCEDURE get_$local_cycle_object_info
    (    cycle_pde: ^fmt$path_description_entry;
         object_info_requests: fst$goi_object_info_requests;
         validation_ring: ost$valid_ring;
         password_validated: boolean;
         p_object: ^fst$goi_object;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      cycle_description: ^fmt$cycle_description,
      eoi: amt$file_byte_address,
      header: ^fmt$static_label_header,
      label_size: ost$non_negative_integers,
      path_handle_p: ^fmt$path_handle;

    status.normal := TRUE;

    initialize_cycle_object (p_object);
    p_object^.cycle_number := cycle_pde^.cycle_number;

    cycle_description := cycle_pde^.cycle_description;
    IF cycle_description = NIL THEN
      RETURN; {----->
    IFEND;

    IF cycle_description^.attached_file THEN
      p_object^.cycle_global_file_name := cycle_description^.system_file_label.descriptive_label.
            internal_cycle_name;
      p_object^.cycle_device_class := cycle_description^.device_class;

      IF fsc$goi_cycle_device_info IN object_info_requests THEN
        pfp$get_attached_device_info ({temporary_file} TRUE, {served_family} FALSE,
              {served_family_locator} NIL, cycle_description, p_object, p_object_information, eoi, status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
      IFEND;
    IFEND;

    IF (fsc$goi_cycle_size IN object_info_requests) AND (p_object^.cycle_device_class =
          rmc$mass_storage_device) THEN
      NEXT p_object^.cycle_size IN p_object_information;
      IF p_object^.cycle_size = NIL THEN
        osp$set_status_condition (pfe$info_full, status);
        RETURN; {----->
      IFEND;
      IF cycle_description^.global_file_information^.eoi_set THEN
        p_object^.cycle_size^ := cycle_description^.global_file_information^.eoi_byte_address;
      ELSEIF cycle_description^.attached_file THEN
        dmp$fetch_eoi (cycle_description^.system_file_id, p_object^.cycle_size^, status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
      ELSE
        p_object^.cycle_size^ := 0;
      IFEND;
    IFEND;

    IF ((fsc$goi_file_label IN object_info_requests) OR (fsc$goi_job_environment_info IN
          object_info_requests)) AND password_validated THEN
      IF cycle_description^.attached_file AND cycle_description^.system_file_label.file_previously_opened THEN
        validate_ring_access (validation_ring, cycle_description^.system_file_label.static_label, status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
      IFEND;

      IF fsc$goi_file_label IN object_info_requests THEN
        IF cycle_description^.attached_file THEN
          IF NOT cycle_description^.system_file_label.file_previously_opened AND
                (cycle_description^.static_setfa_entries <> NIL) THEN
            p_object^.file_label := cycle_description^.system_file_label.static_label;
            fmp$merge_setfa_entries (cycle_description^.static_setfa_entries, p_object, p_object_information,
                  status);
            IF NOT status.normal THEN
              RETURN; {----->
            IFEND;

          ELSEIF cycle_description^.system_file_label.static_label <> NIL THEN
            label_size := #SIZE (cycle_description^.system_file_label.static_label^);
            NEXT p_object^.file_label: [[REP label_size OF cell]] IN p_object_information;
            IF p_object^.file_label = NIL THEN
              osp$set_status_condition (pfe$info_full, status);
              RETURN; {----->
            IFEND;
            i#move (cycle_description^.system_file_label.static_label, p_object^.file_label, label_size);

          ELSE
            label_size := #SIZE (fmt$static_label_header);
            NEXT p_object^.file_label: [[REP label_size OF cell]] IN p_object_information;
            IF p_object^.file_label = NIL THEN
              osp$set_status_condition (pfe$info_full, status);
              RETURN; {----->
            IFEND;

            i#move (^fmv$static_label_header, p_object^.file_label, label_size);
            IF NOT cycle_description^.system_file_label.file_previously_opened THEN
              RESET p_object^.file_label;
              NEXT header IN p_object^.file_label;
              header^.file_previously_opened := FALSE;
            IFEND;
          IFEND;

        ELSEIF cycle_description^.static_setfa_entries <> NIL THEN
          label_size := #SIZE (cycle_description^.static_setfa_entries^);
          NEXT p_object^.file_label: [[REP label_size OF cell]] IN p_object_information;
          IF p_object^.file_label = NIL THEN
            osp$set_status_condition (pfe$info_full, status);
            RETURN; {----->
          IFEND;
          i#move (cycle_description^.static_setfa_entries, p_object^.file_label, label_size);
        IFEND;
      IFEND; { file_label in object_info_requests }

      IF (fsc$goi_job_environment_info IN object_info_requests) AND
            (cycle_description^.attached_file OR (cycle_description^.dynamic_setfa_entries <> NIL)) THEN
        NEXT p_object^.job_environment_information IN p_object_information;
        IF p_object^.job_environment_information = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
        ELSE
          IF cycle_description^.device_class = rmc$connected_file_device THEN
            PUSH path_handle_p;
            path_handle_p^.segment_offset := #OFFSET (cycle_pde);
            path_handle_p^.assignment_counter := cycle_pde^.entry_assignment_counter;
            path_handle_p^.open_position.specified := FALSE;
          ELSE
            path_handle_p := NIL;
          IFEND;
          fmp$setup_job_environment_info (cycle_description, path_handle_p,
                p_object^.job_environment_information, p_object_information);
        IFEND;
      IFEND; { job_environment_info in object_info_requests }
    IFEND;

  PROCEND get_$local_cycle_object_info;

?? TITLE := 'PROCEDURE get_$local_file_object_info', EJECT ??

  PROCEDURE get_$local_file_object_info
    (    cycle_reference: fst$cycle_reference;
         object_info_requests: fst$goi_object_info_requests;
         validation_ring: ost$valid_ring;
         password_validated: boolean;
         p_object: ^fst$goi_object;
     VAR pde: {i/o} ^fmt$path_description_entry;
     VAR p_object_information: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      cycle_count: ost$non_negative_integers,
      cycle_index: ost$positive_integers,
      cycle_pde: ^fmt$path_description_entry,
      local_pde: ^fmt$path_description_entry,
      path: fst$path,
      path_size: fst$path_size;

    status.normal := TRUE;

    p_object^ := initial_file_object;
    p_object^.file_name := pde^.path_node_name.value;

    IF fsc$goi_cycle_object_list IN object_info_requests THEN

{ Get information for all cycles.

      cycle_pde := pde^.highest_cycle;
      cycle_count := 0;
      WHILE cycle_pde <> NIL DO
        IF cycle_pde^.cycle_description <> NIL THEN
          cycle_count := cycle_count + 1;
        IFEND;
        cycle_pde := cycle_pde^.next_lower_cycle;
      WHILEND;

      IF cycle_count > 0 THEN
        NEXT p_object^.cycle_object_list: [1 .. cycle_count] IN p_object_information;
        IF p_object^.cycle_object_list = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
        ELSE
          cycle_pde := pde^.highest_cycle;
          cycle_index := 1;
          WHILE (cycle_pde <> NIL) AND (cycle_index <= cycle_count) DO
            IF cycle_pde^.cycle_description <> NIL THEN
              get_$local_cycle_object_info (cycle_pde, object_info_requests, validation_ring,
                    password_validated, ^p_object^.cycle_object_list^ [cycle_index], p_object_information,
                    status);
              cycle_index := cycle_index + 1;
            IFEND;
            cycle_pde := cycle_pde^.next_lower_cycle;
          WHILEND;
        IFEND;
      IFEND;

    ELSEIF pfv$cycle_info_requests * object_info_requests <> $fst$goi_object_info_requests [] THEN

{ Get information for the highest cycle.

      cycle_pde := pde^.highest_cycle;
      CASE cycle_reference.specification OF
      = fsc$cycle_omitted, fsc$high_cycle =
        get_high_cycle (cycle_pde);
      = fsc$low_cycle =
        get_low_cycle (cycle_pde);
      = fsc$cycle_number =
        locate_cycle (cycle_reference.cycle_number, cycle_pde);
      = fsc$next_cycle =
        get_high_cycle (cycle_pde);
        IF (cycle_pde = NIL) OR cycle_pde^.cycle_description^.attached_file THEN
          recreate_path_string (pde, path, path_size, status);
          IF status.normal THEN
            bap$set_file_reference_abnormal (path (1, path_size), ame$file_not_known,
                  'PFP$GET_OBJECT_INFORMATION', '', status);
          IFEND;
          RETURN; {----->
        IFEND;
      ELSE
      CASEND;

      IF (cycle_pde <> NIL) AND (cycle_pde^.cycle_description <> NIL) THEN
        IF cycle_pde^.cycle_description^.attached_file THEN
          NEXT p_object^.cycle_object_list: [1 .. 1] IN p_object_information;
          IF p_object^.cycle_object_list = NIL THEN
            osp$set_status_condition (pfe$info_full, status);
          ELSE
            get_$local_cycle_object_info (cycle_pde, object_info_requests, validation_ring,
                  password_validated, ^p_object^.cycle_object_list^ [1], p_object_information, status);
          IFEND;
        ELSEIF (object_info_requests * $fst$goi_object_info_requests
              [fsc$goi_file_label, fsc$goi_job_environment_info]) <> $fst$goi_object_info_requests [] THEN

{ A SETFA or REQUEST command is outstanding for an unregistered file so the previously created file_object is
{ irrelevant and should be replaced with a cycle object.

          get_$local_cycle_object_info (cycle_pde, object_info_requests, validation_ring, password_validated,
                p_object, p_object_information, status);
        ELSE
          recreate_path_string (pde, path, path_size, status);
          IF status.normal THEN
            bap$set_file_reference_abnormal (path (1, path_size), ame$file_not_known,
                  'PFP$GET_OBJECT_INFORMATION', '', status);
          IFEND;
          RETURN; {----->
        IFEND;
        pde := cycle_pde;
      ELSE
        recreate_path_string (pde, path, path_size, status);
        IF status.normal THEN
          bap$set_file_reference_abnormal (path (1, path_size), ame$file_not_known,
                'PFP$GET_OBJECT_INFORMATION', '', status);
        IFEND;
      IFEND;
    IFEND;

  PROCEND get_$local_file_object_info;

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

  PROCEDURE [INLINE] increment_assignment_counter;

    IF fmv$pde_assignment_counter >= UPPERVALUE (fmt$pde_assignment_counter) THEN
      fmv$pde_assignment_counter := LOWERVALUE (fmt$pde_assignment_counter) + 1;
    ELSE
      fmv$pde_assignment_counter := fmv$pde_assignment_counter + 1;
    IFEND;

  PROCEND increment_assignment_counter;

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

  PROCEDURE [INLINE] insert_cycle_object
    (    cycle_object: ^fmt$path_description_entry);

{ PURPOSE: This procedure takes a cycle_object and inserts it in the
{          proper place in a linked list of cycle_objects.  The named
{          object is updated to reflect the addition.

    VAR
      next_lower_cycle: ^fmt$path_description_entry,
      next_higher_cycle: ^fmt$path_description_entry;

    IF cycle_object^.parental_path_entry^.highest_cycle <> NIL THEN
      IF cycle_object^.parental_path_entry^.highest_cycle^.cycle_number < cycle_object^.cycle_number THEN

{ Make cycle_object the new highest_cycle.

        cycle_object^.next_lower_cycle := cycle_object^.parental_path_entry^.highest_cycle;
        cycle_object^.parental_path_entry^.highest_cycle^.next_higher_cycle := cycle_object;
        cycle_object^.parental_path_entry^.highest_cycle := cycle_object;
        cycle_object^.next_higher_cycle := NIL;
      ELSE
        next_lower_cycle := cycle_object^.parental_path_entry^.highest_cycle^.next_lower_cycle;
        next_higher_cycle := cycle_object^.parental_path_entry^.highest_cycle;

{ Find insertion point.

        WHILE (next_lower_cycle <> NIL) AND (next_lower_cycle^.cycle_number > cycle_object^.cycle_number) DO
          next_higher_cycle := next_lower_cycle;
          next_lower_cycle := next_lower_cycle^.next_lower_cycle;
        WHILEND;

{ Change cycle_object to point to next higher and lower cycles.

        cycle_object^.next_lower_cycle := next_lower_cycle;
        cycle_object^.next_higher_cycle := next_higher_cycle;

{ Change higher and lower to point to inserted cycle_object.

        IF next_lower_cycle <> NIL THEN
          next_lower_cycle^.next_higher_cycle := cycle_object;
        IFEND;
        IF next_higher_cycle <> NIL THEN
          next_higher_cycle^.next_lower_cycle := cycle_object;
        IFEND;
      IFEND;
    ELSE { no existing cycles }
      cycle_object^.parental_path_entry^.highest_cycle := cycle_object;
      cycle_object^.next_lower_cycle := NIL;
      cycle_object^.next_higher_cycle := NIL;
    IFEND;

  PROCEND insert_cycle_object;

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

  PROCEDURE [INLINE] get_high_cycle
    (VAR cycle_pde: ^fmt$path_description_entry);

    WHILE (cycle_pde <> NIL) AND (cycle_pde^.cycle_description = NIL) DO
      cycle_pde := cycle_pde^.next_lower_cycle;
    WHILEND;

  PROCEND get_high_cycle;

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

  PROCEDURE [INLINE] get_low_cycle
    (VAR cycle_pde: ^fmt$path_description_entry);

    IF cycle_pde <> NIL THEN

{ move to bottom of linked list of cycles

      WHILE cycle_pde^.next_lower_cycle <> NIL DO
        cycle_pde := cycle_pde^.next_lower_cycle;
      WHILEND;

      WHILE (cycle_pde <> NIL) AND (cycle_pde^.cycle_description = NIL) DO
        cycle_pde := cycle_pde^.next_higher_cycle;
      WHILEND;
    IFEND;

  PROCEND get_low_cycle;

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

  PROCEDURE get_path_cycle
    (    resolve_to_catalog: boolean;
         resolve_pf_in_pt: boolean;
         local_path: boolean;
     VAR evaluated_file_reference: {i/o} fst$evaluated_file_reference;
     VAR cycle_pde: {i/o} ^fmt$path_description_entry;
     VAR status: ost$status);

*copy fsh$resolve_path

    VAR
      p_path: ^pft$path,
      pf_path_resolution: fst$path_resolution;

    status.normal := TRUE;

    IF evaluated_file_reference.number_of_path_elements = 1 THEN
      IF local_path THEN
        IF evaluated_file_reference.cycle_reference.specification = fsc$cycle_omitted THEN
          evaluated_file_reference.path_resolution := fsc$catalog_path;
        ELSE
          osp$set_status_abnormal (amc$access_method_id, fse$catalogs_do_not_have_cycles, fsc$local, status);
        IFEND;
      ELSE { permanent_file }
        osp$set_status_abnormal (amc$access_method_id, pfe$path_too_short,
              fsp$path_element (^evaluated_file_reference, 1) ^, status);
        osp$append_status_integer (osc$status_parameter_delimiter, 2, 10, FALSE, status);
        osp$append_status_parameter (osc$status_parameter_delimiter, 'path', status);
      IFEND;
      cycle_pde := NIL;
      RETURN; {----->
    IFEND;

    IF local_path OR ((NOT resolve_to_catalog) AND resolve_pf_in_pt) THEN
      IF cycle_pde = NIL THEN { no high cycle to start from }
        IF local_path THEN
          IF evaluated_file_reference.cycle_reference.specification <> fsc$cycle_number THEN
            evaluated_file_reference.cycle_reference.specification := fsc$cycle_number;
            evaluated_file_reference.cycle_reference.cycle_number := 1;
          IFEND;
        IFEND;
      ELSE
        resolve_in_path_table (local_path, evaluated_file_reference, cycle_pde, status);
      IFEND;

    ELSE { permanent_file }
      IF resolve_to_catalog THEN
        PUSH p_path: [1 .. evaluated_file_reference.number_of_path_elements];
        pfp$convert_fs_to_pft$path (evaluated_file_reference, p_path^);
        pfp$resolve_path (p_path^, evaluated_file_reference.cycle_reference, pf_path_resolution, status);
        IF status.normal THEN
          evaluated_file_reference.path_resolution := pf_path_resolution;
        IFEND;
      IFEND; {resolve to catalog

{     set cycle_pde back to NIL so that a new cycle_object will
{     be created if bac$record_path IN process_pt_work_list

      cycle_pde := NIL;
    IFEND; {local file or resolve_pf_in_pt}

  PROCEND get_path_cycle;

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

  PROCEDURE [INLINE] initialize_cycle_object
    (    p_object: ^fst$goi_object);

    p_object^ := initial_cycle_object;
    p_object^.cycle_global_file_name := pfv$null_unique_name;

  PROCEND initialize_cycle_object;

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

  PROCEDURE [INLINE] locate_cycle
    (    cycle_number: fst$cycle_number;
     VAR cycle_pde: ^fmt$path_description_entry);

    WHILE (cycle_pde <> NIL) AND (cycle_pde^.cycle_number <> cycle_number) DO
      cycle_pde := cycle_pde^.next_lower_cycle;
    WHILEND;

  PROCEND locate_cycle;

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

  PROCEDURE locate_entry_via_path
    (    process_pt_work_list: bat$process_pt_work_list;
     VAR evaluated_file_reference: fst$evaluated_file_reference;
     VAR found_or_created: boolean;
     VAR path_description_entry: ^fmt$path_description_entry;
     VAR status: ost$status);

{ PURPOSE: This procedure will follow a path, creating the path nodes as
{          it goes if creation is specified.

    VAR
      element_index: fst$path_index,
      element_offset: fst$path_index,
      element_size: 1 .. fsc$max_path_element_size,
      local_cycle: ^fmt$path_description_entry,
      local_file_name: amt$local_file_name,
      local_path: boolean,
      local_pde_is_alias: boolean,
      next_pde: ^fmt$path_description_entry,
      path_node_name: fst$path_element,
      potential_alias: amt$local_file_name,
      resolve_path: boolean,
      starting_element: fst$path_index;

    status.normal := TRUE;

    path_description_entry := NIL;
    local_cycle := NIL;
    found_or_created := FALSE;

    resolve_path := bac$resolve_path IN process_pt_work_list;

{ Check for a valid evaluated_file_reference.  Either a path_handle must be present OR the number of path
{ elements must be nonzero.

    IF evaluated_file_reference.path_handle_info.path_handle_present THEN
      fmp$locate_pde_via_path_handle (evaluated_file_reference.path_handle_info.path_handle,
            path_description_entry, status);
      IF NOT status.normal THEN

{ Reinitialize the path_handle_info. Set path_handle_present := FALSE & set path_handle to defaults.

        evaluated_file_reference.path_handle_info := fsv$evaluated_file_reference.path_handle_info;
        IF (status.condition = fme$obsolete_path_handle) AND
              (evaluated_file_reference.number_of_path_elements > 0) THEN

{ Attempt to reference the path via the path_structure.

          status.normal := TRUE;
        ELSE
          RETURN; {----->
        IFEND;
      ELSE {status.normal = TRUE

{ Cross validate the path_handle and path_structure.
{ Either: 1) The path depths must equal. OR
{         2) The path depth of structure must be 0. OR
{         3) The path structure must an alias of the file the path_handle represents.

        IF (path_description_entry^.path_depth <> evaluated_file_reference.number_of_path_elements) THEN
          IF (path_description_entry^.entry_type = fmc$file_cycle_object) AND
                (path_description_entry^.first_cycle_alias_entry <> NIL) AND
                (evaluated_file_reference.number_of_path_elements = 2) THEN
            IF fsp$path_element (^evaluated_file_reference, 1) ^ = fsc$local THEN
              potential_alias := fsp$path_element (^evaluated_file_reference, 2) ^;
              next_pde := path_description_entry^.first_cycle_alias_entry;
              WHILE (next_pde <> NIL) AND (evaluated_file_reference.number_of_path_elements = 2) DO
                IF next_pde^.path_node_name.value = potential_alias THEN
                  evaluated_file_reference.number_of_path_elements := 0;
                ELSE
                  next_pde := next_pde^.next_cycle_alias_entry;
                IFEND;
              WHILEND;
            IFEND;
          IFEND;
          IF evaluated_file_reference.number_of_path_elements = 0 THEN
            recreate_path_elements (path_description_entry, evaluated_file_reference);
          ELSE
            osp$set_status_abnormal (amc$access_method_id, fme$system_error,
                  ' - mismatched evaluated_file_reference and path_handle', status);
            RETURN; {----->
          IFEND;
        IFEND; {path_depth <> number_of_path_elements.
        found_or_created := TRUE;
        IF path_description_entry^.entry_type = fmc$file_cycle_object THEN
          evaluated_file_reference.path_resolution := fsc$cycle_path;
          local_path := (fsp$path_element (^evaluated_file_reference, 1) ^ = fsc$local);
          RETURN; {----->
        IFEND;
      IFEND;
    ELSEIF evaluated_file_reference.number_of_path_elements <= 0 THEN
      osp$set_status_abnormal (amc$access_method_id, fme$system_error,
            ' - uninitialized evaluated_file_reference ', status);
      RETURN; {----->
    IFEND;

    local_path := (fsp$path_element (^evaluated_file_reference, 1) ^ = fsc$local);

{ Do local file validation.

    IF local_path THEN
      IF evaluated_file_reference.number_of_path_elements = 2 THEN
        IF fsp$path_element (^evaluated_file_reference, 2) ^ = clc$null_file THEN
          IF (path_description_entry = NIL) OR (path_description_entry^.entry_type <> fmc$file_cycle_object)
                THEN
            resolve_path := TRUE;
          IFEND;
        IFEND;
      ELSEIF evaluated_file_reference.number_of_path_elements > 2 THEN
        osp$set_status_abnormal (amc$access_method_id, fse$local_subcatalog_illegal,
              fsp$path_element (^evaluated_file_reference, 2) ^, status);
        evaluated_file_reference.path_resolution := fsc$path_resolution_error;
        RETURN; {----->
      IFEND;
    IFEND;

{ Find or create the path elements.

    IF path_description_entry = NIL THEN
      IF local_path THEN
        next_pde := fmv$local_pde;
        element_offset := fmc$local_offset;
        starting_element := 2;
      ELSE
        next_pde := NIL;
        element_offset := 1;
        starting_element := 1;
      IFEND;

      FOR element_index := starting_element TO evaluated_file_reference.number_of_path_elements DO
        element_size := $INTEGER (evaluated_file_reference.path_structure (element_offset));
        path_node_name.value := evaluated_file_reference.path_structure (element_offset + 1, element_size);
        path_node_name.size := element_size;

        locate_named_object (path_node_name, {parent=} next_pde, bac$record_path IN process_pt_work_list,
              found_or_created, next_pde);
        IF NOT found_or_created THEN
          evaluated_file_reference.path_resolution := fsc$path_resolution_error;
          RETURN; {----->
        IFEND;

        element_offset := element_offset + element_size + 1;
      FOREND;

      path_description_entry := next_pde;
      evaluated_file_reference.path_handle_info.path_handle.segment_offset :=
            #OFFSET (path_description_entry);
      evaluated_file_reference.path_handle_info.path_handle.assignment_counter :=
            path_description_entry^.entry_assignment_counter;
      evaluated_file_reference.path_handle_info.path_handle_present := TRUE;

{ Update statistics.

      IF path_description_entry^.path_depth > fmv$max_path_depth THEN
        fmv$max_path_depth := path_description_entry^.path_depth
      IFEND;
      IF path_description_entry^.path_depth <= fmc$statistics_max_path_depth THEN
        fmv$path_depth_entries [path_description_entry^.path_depth] :=
              fmv$path_depth_entries [path_description_entry^.path_depth] + 1;
      ELSE
        fmv$path_depth_entries [fmc$statistics_max_path_depth] :=
              fmv$path_depth_entries [fmc$statistics_max_path_depth] + 1;
      IFEND;

    IFEND; { path_description_entry = NIL }

{ Resolve.

    local_pde_is_alias := pde_is_alias (path_description_entry);
    IF local_pde_is_alias THEN
      IF NOT (bac$leave_aliases_unresolved IN process_pt_work_list) THEN
        local_cycle := path_description_entry^.highest_cycle;
        recreate_path_elements (local_cycle, evaluated_file_reference);
      ELSE
        evaluated_file_reference.cycle_reference.specification := fsc$cycle_omitted;
      IFEND;
    ELSEIF resolve_path AND (evaluated_file_reference.cycle_reference.specification <> fsc$cycle_number) THEN
      local_cycle := path_description_entry^.highest_cycle;
      get_high_cycle (local_cycle); {find the highest cycle description.
      IF local_path OR (bac$record_path IN process_pt_work_list) OR (local_cycle <> NIL) THEN

{ Do not resolve a permanent file unless either a cycle_description exists OR record_path was specified.

        get_path_cycle (bac$resolve_to_catalog IN process_pt_work_list,
              bac$resolve_pf_in_pt IN process_pt_work_list, local_path, evaluated_file_reference, local_cycle,
              status);
        IF NOT status.normal THEN
          evaluated_file_reference.path_resolution := fsc$path_resolution_error;
          RETURN; {----->
        IFEND;
      ELSE

{ Note: path_resolution is already set to fsc$unresolved_path.

        RETURN; {----->
      IFEND;
    IFEND;

{ Update VAR parameters - path_handle, path_resolution, path_description_entry, found & created.

    IF evaluated_file_reference.cycle_reference.specification = fsc$cycle_number THEN
      IF local_cycle = NIL THEN

{ Look for local_cycle to match cycle_number.

        local_cycle := path_description_entry^.highest_cycle;
        locate_cycle (evaluated_file_reference.cycle_reference.cycle_number, local_cycle);
      IFEND;
      IF local_cycle <> NIL THEN
        found_or_created := TRUE;
        evaluated_file_reference.path_resolution := fsc$cycle_path;
      ELSEIF bac$record_path IN process_pt_work_list THEN
        create_cycle_object (evaluated_file_reference.cycle_reference.cycle_number, path_description_entry,
              local_cycle);
        found_or_created := TRUE;
        evaluated_file_reference.path_resolution := fsc$new_cycle_path;
      ELSE
        found_or_created := FALSE;

{ Note: path_resolution is already set to fsc$unresolved_path

        RETURN; {----->
      IFEND;
      IF local_cycle <> NIL THEN
        path_description_entry := local_cycle;
        evaluated_file_reference.path_handle_info.path_handle.segment_offset :=
              #OFFSET (path_description_entry);
        evaluated_file_reference.path_handle_info.path_handle.assignment_counter :=
              path_description_entry^.entry_assignment_counter;
        evaluated_file_reference.path_handle_info.path_handle_present := TRUE;
      IFEND;
    IFEND;

  PROCEND locate_entry_via_path;

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

  PROCEDURE [INLINE] locate_named_object
    (    path_node_name: fst$path_element;
         parental_path_entry: ^fmt$path_description_entry;
         create: boolean;
     VAR found_or_created: boolean;
     VAR pde: ^fmt$path_description_entry);

    VAR
      randomized_node_name: ost$randomized_name,
      parental_tree_entry: ^fmt$path_description_entry,
      node: ^fmt$path_description_entry;

{ Start search from offset of node passed into procedure.

    node := fmv$path_table_entry_point;
    parental_tree_entry := NIL;

    osp$randomize_name (path_node_name.value, randomized_node_name);

    WHILE node <> NIL DO
      IF (randomized_node_name = node^.randomized_node_name) AND (path_node_name = node^.path_node_name) AND
            (parental_path_entry = node^.parental_path_entry) THEN
        pde := node;
        found_or_created := TRUE;
        RETURN; {----->
      IFEND;

      IF randomized_node_name < node^.randomized_node_name THEN
{ Go left
        parental_tree_entry := node;
        node := node^.left_subtree;
      ELSE { >= } { includes collisions }
{ Go right
        parental_tree_entry := node;
        node := node^.right_subtree;
      IFEND;
    WHILEND;

{ Only gets to here if a named_object was not found.

    IF create THEN
      create_named_object (parental_path_entry, parental_tree_entry, path_node_name, randomized_node_name,
            pde);
      found_or_created := TRUE;
    ELSE

{ A named_object has not been found or created so return a pointer
{ to the last named_object to which the named_object would be
{ attached if it had been created.  This allows changes to attach
{ an already existing pde to this node.

      pde := parental_tree_entry;
      found_or_created := FALSE;
    IFEND;

  PROCEND locate_named_object;

?? TITLE := 'FUNCTION [INLINE] pde_is_alias', EJECT ??

  FUNCTION [INLINE] pde_is_alias
    (    pde: ^fmt$path_description_entry): boolean;

    pde_is_alias := (pde^.entry_type = fmc$named_object) AND (pde^.highest_cycle <> NIL) AND
          (pde^.highest_cycle^.parental_path_entry <> pde);

  FUNCEND pde_is_alias;

?? TITLE := 'FUNCTION [INLINE] pdes_first_element_is_$local', EJECT ??

  FUNCTION [INLINE] pdes_first_element_is_$local
    (    pde: ^fmt$path_description_entry): boolean;

    VAR
      temp_pde: ^fmt$path_description_entry;

    temp_pde := pde;
    WHILE temp_pde^.parental_path_entry <> NIL DO
      temp_pde := temp_pde^.parental_path_entry;
    WHILEND;
    pdes_first_element_is_$local := (temp_pde^.path_node_name = fmv$local_node_name);

  FUNCEND pdes_first_element_is_$local;

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

  PROCEDURE [INLINE] recreate_path_elements
    (    starting_pde: ^fmt$path_description_entry;
     VAR evaluated_file_reference: fst$evaluated_file_reference);

{ PURPOSE: Given a path_description_entry, recreate a path to that node.
{          An array of path elements and a cycle_reference is returned.

    VAR
      cycle_string: ost$string,
      element_offset: fst$path_index,
      pde: ^fmt$path_description_entry;

    pde := starting_pde;

{ Fill in cycle number if file cycle object.
{ Note: path depth is the same in last element and it's cycle objects

    evaluated_file_reference.number_of_path_elements := pde^.path_depth;

{ Fill in cycle number if file cycle object.

    IF pde^.entry_type = fmc$file_cycle_object THEN
      evaluated_file_reference.cycle_reference.specification := fsc$cycle_number;
      evaluated_file_reference.cycle_reference.cycle_number := pde^.cycle_number;

{ Move up the tree.

      pde := pde^.parental_path_entry;
    IFEND;

{ calculate the size of the path elements part of path

    evaluated_file_reference.path_structure_size := pde^.cumulative_parental_path_size + 1 +
          pde^.path_node_name.size;

{ Fill in each path element name from last to first.

    REPEAT
      element_offset := pde^.cumulative_parental_path_size + 1;

{ fill in path_structure

      evaluated_file_reference.path_structure (element_offset) := $CHAR (pde^.path_node_name.size);
      evaluated_file_reference.path_structure (element_offset + 1, pde^.path_node_name.size) :=
            pde^.path_node_name.value;

{ move pde to parental path entry

      pde := pde^.parental_path_entry;
    UNTIL pde = NIL;

  PROCEND recreate_path_elements;

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

  PROCEDURE [INLINE] recreate_path_string
    (    starting_pde: ^fmt$path_description_entry;
     VAR path: fst$path;
     VAR path_size: fst$path_size;
     VAR status: ost$status);

{ PURPOSE: Given a path_description_entry, recreate a path to that node.
{          A string containing the path is returned.

    VAR
      cycle_string: ost$string,
      element_offset: fst$path_index,
      pde: ^fmt$path_description_entry;

    status.normal := TRUE;
    pde := starting_pde;
    path := osc$null_name;
    path_size := 0;

{ Note: path depth is the same in last element and it's cycle objects

{ Fill in cycle number if file cycle object.

    IF pde^.entry_type = fmc$file_cycle_object THEN
      clp$convert_integer_to_string (pde^.cycle_number, 10, FALSE, cycle_string, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;
      path_size := pde^.cumulative_parental_path_size + cycle_string.size + 1;
      IF path_size > fsc$max_path_size THEN
        path_size := 0;
        osp$set_status_abnormal (amc$access_method_id, cle$file_reference_too_long, 'recreate_path_string',
              status);
        RETURN; {----->
      IFEND;
      path (pde^.cumulative_parental_path_size + 1, 1) := '.';
      path (pde^.cumulative_parental_path_size + 2, cycle_string.size) := cycle_string.value;

{ Move up the tree.

      pde := pde^.parental_path_entry;
    ELSE
      path_size := pde^.cumulative_parental_path_size + pde^.path_node_name.size + 1;
    IFEND;

{ Fill in each path element name from last to first.

    REPEAT
      element_offset := pde^.cumulative_parental_path_size + 1;

{ fill in element delimiter

      path (element_offset, 1) := '.';

{ fill in element name

      path (element_offset + 1, pde^.path_node_name.size) := pde^.path_node_name.value;

{ move pde to parental path entry

      pde := pde^.parental_path_entry;
    UNTIL pde = NIL;
    path (1, 1) := ':';

  PROCEND recreate_path_string;

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

  PROCEDURE release_object
    (VAR pde: ^fmt$path_description_entry);

{ PURPOSE: This procedure frees any object entry.

    VAR
      entry_assignment_pointer: ^string (1);

    IF pde^.entry_type = fmc$named_object THEN
      fmv$named_objects_deleted := fmv$named_objects_deleted + 1;
    ELSE { cycle_object }
      fmv$cycle_objects_deleted := fmv$cycle_objects_deleted + 1;
    IFEND;
    IF pde^.parental_path_entry <> NIL THEN
      pde^.parental_path_entry^.active_path_participation_count :=
            pde^.parental_path_entry^.active_path_participation_count - 1;
    IFEND;
    pde^.pdu_pointer^.current_count := pde^.pdu_pointer^.current_count - 1;
    pde^.entry_assignment^ := fmc$entry_free;
    entry_assignment_pointer := pde^.entry_assignment;
    pde^ := fmv$default_pde;
    pde^.entry_assignment := entry_assignment_pointer;
    pde := NIL;

  PROCEND release_object;

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

  PROCEDURE resolve_in_path_table
    (    local_path: boolean;
     VAR evaluated_file_reference: {i/o} fst$evaluated_file_reference;
     VAR cycle_pde: {i/o} ^fmt$path_description_entry;
     VAR status: ost$status);

    VAR
      path: fst$path,
      path_size: fst$path_size;

    CASE evaluated_file_reference.cycle_reference.specification OF
    = fsc$cycle_omitted, fsc$high_cycle =
      get_high_cycle (cycle_pde);
      IF (cycle_pde <> NIL) THEN
        evaluated_file_reference.cycle_reference.specification := fsc$cycle_number;
        evaluated_file_reference.cycle_reference.cycle_number := cycle_pde^.cycle_number;
      ELSE
        IF (evaluated_file_reference.cycle_reference.specification = fsc$high_cycle) THEN

{ this should be changed to put out and error is create is true

          evaluated_file_reference.cycle_reference.specification := fsc$cycle_omitted;
        ELSEIF local_path THEN
          evaluated_file_reference.cycle_reference.specification := fsc$cycle_number;
          evaluated_file_reference.cycle_reference.cycle_number := 1;
        IFEND;
      IFEND;

    = fsc$low_cycle =
      get_low_cycle (cycle_pde);
      IF (cycle_pde <> NIL) THEN
        evaluated_file_reference.cycle_reference.specification := fsc$cycle_number;
        evaluated_file_reference.cycle_reference.cycle_number := cycle_pde^.cycle_number;
      ELSE

{ this should be changed to put out and error is create is true

        evaluated_file_reference.cycle_reference.specification := fsc$cycle_omitted;
      IFEND;

    = fsc$next_cycle =
      get_high_cycle (cycle_pde);
      IF cycle_pde <> NIL THEN
        IF cycle_pde^.cycle_number + 1 < fsc$maximum_cycle_number THEN
          evaluated_file_reference.cycle_reference.specification := fsc$cycle_number;
          evaluated_file_reference.cycle_reference.cycle_number := cycle_pde^.cycle_number + 1;

{set cycle_pde back to NIL so that a new cycle_object will
{be created if bac$record_path IN process_pt_work_list

          cycle_pde := NIL;
        ELSE

{set cycle_pde back to parent named object so cycle not in path

          cycle_pde := cycle_pde^.parental_path_entry;
          recreate_path_string (cycle_pde, path, path_size, status);
          osp$set_status_abnormal (amc$access_method_id, pfe$cycle_overflow, path (1, path_size), status);
        IFEND;
      ELSE
        evaluated_file_reference.cycle_reference.specification := fsc$cycle_number;
        evaluated_file_reference.cycle_reference.cycle_number := 1;
      IFEND;

    = fsc$cycle_number =
      locate_cycle (evaluated_file_reference.cycle_reference.cycle_number, cycle_pde);

    ELSE
      osp$set_status_condition (pfe$bad_cycle_option, status);
      osp$append_status_integer (osc$status_parameter_delimiter,
            $INTEGER (evaluated_file_reference.cycle_reference.specification), 10, FALSE, status);
    CASEND;

  PROCEND resolve_in_path_table;

?? TITLE := 'sort_directory', EJECT ??

  PROCEDURE sort_directory
    (    directory: pft$p_directory_array);

    VAR
      gap: integer,
      start: integer,
      current: integer,
      swap: pft$directory_array_entry;

{ Use shell sort technique.

    gap := UPPERBOUND (directory^);
    WHILE gap > 1 DO
      gap := 2 * (gap DIV 4) + 1;
      FOR start := 1 TO UPPERBOUND (directory^) - gap DO
        current := start;
        WHILE (current > 0) AND (directory^ [current].name > directory^ [current + gap].name) DO
          swap := directory^ [current];
          directory^ [current] := directory^ [current + gap];
          directory^ [current + gap] := swap;
          current := current - gap;
        WHILEND;
      FOREND;
    WHILEND;

  PROCEND sort_directory;

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

  PROCEDURE [INLINE] validate_default_ring_access
    (    validation_ring: ost$valid_ring;
     VAR status: ost$status);

    IF (validation_ring > fmv$system_file_attributes.static_label.ring_attributes.r3) AND
          (avp$ring_min () > fmv$system_file_attributes.static_label.ring_attributes.r3) THEN
      osp$set_status_condition (ame$ring_validation_error, status);
    IFEND;

  PROCEND validate_default_ring_access;

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

  PROCEDURE [INLINE] validate_ring_access
    (    validation_ring: ost$valid_ring;
         static_label: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      header: ^fmt$static_label_header,
      local_static_label: ^SEQ ( * );

    status.normal := TRUE;
    local_static_label := static_label;

    IF local_static_label <> NIL THEN
      RESET local_static_label;
      NEXT header IN local_static_label;
      IF (header <> NIL) AND (header^.file_previously_opened) AND
            (validation_ring > header^.ring_attributes.r3) AND (avp$ring_min () >
            header^.ring_attributes.r3) THEN
        osp$set_status_condition (ame$ring_validation_error, status);
      IFEND;
    ELSE
      validate_default_ring_access (validation_ring, status);
    IFEND;

  PROCEND validate_ring_access;
?? OLDTITLE ??
MODEND fmm$path_table_manager;
