?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE File System : SETFA Processing' ??
MODULE fmm$setfa_processing;

{ PURPOSE:
{   This module contains the procedures that process SETFA information.

?? NEWTITLE := 'Global Declaration Referenced by this Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc amc$condition_code_limits
*copyc ame$attribute_validation_errors
*copyc amt$entry_point_reference
*copyc amt$file_attributes
*copyc amt$file_reference
*copyc fmc$current_revision_level
*copyc fmc$unique_label_id
*copyc fme$file_management_errors
*copyc fmt$cycle_description
*copyc fmt$file_attribute_keys
*copyc fmt$static_label_header
*copyc fmt$static_label_item
*copyc fse$get_info_validation_errors
*copyc fst$goi_object
*copyc fst$goi_object_information
*copyc fst$job_environment_information
*copyc fst$goi_object_info_requests
*copyc fst$open_position
*copyc oss$job_paged_literal
*copyc pfe$internal_error_conditions
?? POP ??
*copyc bap$merge_dynamic_attr_source
*copyc bap$set_file_reference_abnormal
*copyc fmp$catalog_system_file_label
*copyc fmp$evaluate_path
*copyc fmp$extract_dynamic_setfa_attrs
*copyc fmp$setup_job_environment_info
*copyc fmp$unlock_path_table
*copyc fsp$convert_file_contents
*copyc fsp$convert_to_old_contents
*copyc i#current_sequence_position
*copyc i#move
*copyc osp$append_status_parameter
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc fmv$static_label_header
*copyc fmv$system_file_attributes
*copyc osv$job_pageable_heap

  CONST
    last_attribute_key = 76;

  TYPE
    char_set = set of char;

  VAR
    default_dynamic_setfa_entries: [STATIC, READ, oss$job_paged_literal] fst$setfa_attachment_options :=
          [FALSE, * , FALSE, * , FALSE, * , FALSE, * , FALSE, * , FALSE, * ],

    space_selector: [STATIC, READ, oss$job_paged_literal] char_set := [' '];

  VAR
    file_label_key: [STATIC, READ, oss$job_paged_literal] array [1 .. last_attribute_key] of
          fmt$file_attribute_keys := [

    {amc$access_level .............. = 001} amc$max_attribute,
          {amc$access_mode ............... = 002} amc$max_attribute,
          {amc$application_info .......... = 003} amc$max_attribute,
          {amc$average_record_length ..... = 004} fmc$average_record_length,
          {amc$block_type ................ = 005} fmc$block_type,
          {amc$character_conversion ...... = 006} fmc$character_conversion,
          {amc$clear_space ............... = 007} fmc$clear_space,
          {amc$collate_table ............. = 008} fmc$collate_table,
          {amc$collate_table_name ........ = 009} fmc$collate_table_name,
          {............................... = 010} amc$max_attribute,
          {............................... = 011} amc$max_attribute,
          {amc$data_padding .............. = 012} fmc$data_padding,
          {amc$embedded_key .............. = 013} fmc$embedded_key,
          {amc$error_exit_name ........... = 014} amc$max_attribute,
          {amc$error_exit_procedure ...... = 015} amc$max_attribute,
          {amc$error_limit ............... = 016} amc$max_attribute,
          {amc$error_options ............. = 017} amc$max_attribute,
          {amc$estimated_record_count .... = 018} fmc$estimated_record_count,
          {amc$file_access_procedure ..... = 019} fmc$file_access_procedure,
          {amc$file_contents ............. = 020} fmc$file_contents,
          {amc$file_length ............... = 021} amc$max_attribute,
          {amc$file_limit ................ = 022} fmc$file_limit,
          {............................... = 023} amc$max_attribute,
          {amc$file_organization ......... = 024} fmc$file_organization,
          {amc$file_processor ............ = 025} fmc$file_processor,
          {amc$file_structure ............ = 026} fmc$file_structure,
          {amc$forced_write .............. = 027} fmc$forced_write,
          {amc$global_access_mode ........ = 028} amc$max_attribute,
          {amc$global_file_address ....... = 029} amc$max_attribute,
          {amc$global_file_position ...... = 030} amc$max_attribute,
          {amc$global_file_name .......... = 031} amc$max_attribute,
          {amc$global_share_mode ......... = 032} amc$max_attribute,
          {amc$index_levels .............. = 033} fmc$index_levels,
          {amc$index_padding ............. = 034} fmc$index_padding,
          {amc$internal_code ............. = 035} fmc$internal_code,
          {amc$key_length ................ = 036} fmc$key_length,
          {amc$key_position .............. = 037} fmc$key_position,
          {amc$key_type .................. = 038} fmc$key_type,
          {amc$label_exit_name ........... = 039} amc$max_attribute,
          {amc$label_exit_procedure ...... = 040} amc$max_attribute,
          {amc$label_options ............. = 041} amc$max_attribute,
          {amc$label_type ................ = 042} fmc$label_type,
          {............................... = 043} amc$max_attribute,
          {amc$line_number ............... = 044} fmc$line_number,
          {amc$max_block_length .......... = 045} fmc$max_block_length,
          {amc$max_record_length ......... = 046} fmc$max_record_length,
          {amc$message_control ........... = 047} amc$max_attribute,
          {amc$min_block_length .......... = 048} fmc$min_block_length,
          {amc$min_record_length ......... = 049} fmc$min_record_length,
          {amc$null_attribute ............ = 050} amc$max_attribute,
          {amc$open_position ............. = 051} amc$max_attribute,
          {amc$padding_character ......... = 052} fmc$padding_character,
          {amc$page_format ............... = 053} fmc$page_format,
          {amc$page_length ............... = 054} fmc$page_length,
          {amc$page_width ................ = 055} fmc$page_width,
          {amc$permanent_file ............ = 056} amc$max_attribute,
          {amc$preset_value .............. = 057} fmc$preset_value,
          {............................... = 058} amc$max_attribute,
          {amc$record_limit .............. = 059} fmc$record_limit,
          {amc$record_type ............... = 060} fmc$record_type,
          {amc$records_per_block ......... = 061} fmc$records_per_block,
          {amc$return_option ............. = 062} amc$max_attribute,
          {amc$ring_attributes ........... = 063} fmc$ring_attributes,
          {amc$statement_identifier ...... = 064} fmc$statement_identifier,
          {............................... = 065} amc$max_attribute,
          {amc$user_info ................. = 066} fmc$user_info,
          {amc$vertical_print_density .... = 067} fmc$vertical_print_density,
          {amc$compression_procedure_name  = 068} fmc$compression_procedure_name,
          {amc$dynamic_home_block_space .. = 069} fmc$dynamic_home_block_space,
          {amc$hashing_procedure_name .... = 070} fmc$hashing_procedure_name,
          {amc$initial_home_block_count .. = 071} fmc$initial_home_block_count,
          {amc$loading_factor ............ = 072} fmc$loading_factor,
          {amc$lock_expiration_time ...... = 073} fmc$lock_expiration_time,
          {amc$logging_options ........... = 074} fmc$logging_options,
          {amc$log_residence ............. = 075} fmc$log_residence,
          {............................... = xxx} amc$max_attribute];

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

  PROCEDURE [XDCL] fmp$catalog_set_file_attributes
    (    cycle_description: ^fmt$cycle_description;
     VAR status: ost$status);

    VAR
      system_file_label: fmt$system_file_label;

{ This routine is only called if cycle_description^.system_file_label.
{ file_previously_opened = FALSE.

    status.normal := TRUE;

    system_file_label.file_previously_opened := FALSE;
    system_file_label.static_label := cycle_description^.static_setfa_entries;

    IF (system_file_label.static_label <> NIL) OR (cycle_description^.job_routing_label <> NIL) THEN
      fmp$catalog_system_file_label (^system_file_label, cycle_description^.job_routing_label,
            cycle_description^.job_routing_label_length, cycle_description^.apfid, pfc$append, status);
    IFEND;
  PROCEND fmp$catalog_set_file_attributes;

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

  PROCEDURE [XDCL, #GATE] fmp$file_command
    (    file: fst$file_reference;
         file_attributes: ^amt$file_attributes;
     VAR status: ost$status);

    TYPE
      file_attribute_keys = set of amt$file_attribute_keys,
      fmt$entry_kind = (fmc$setfa_entry, fmc$label_entry);

    VAR
      attribute_index: amt$file_attribute_keys,
      converted_file_contents: amt$file_contents,
      current_file_structure_p: ^string ( * ),
      cycle_description: ^fmt$cycle_description,
      existing_str: ^string ( * ),
      header: ^fmt$static_label_header,
      ignore_evaluated_file_reference: fst$evaluated_file_reference,
      ignore_found: boolean,
      ignore_path_handle: fmt$path_handle,
      item: ^fmt$static_label_item,
      label_index: fmt$file_attribute_keys,
      label_item_replaced: boolean,
      new_setfa_label: ^SEQ ( * ),
      previous_file_contents_p: ^string ( * ),
      path_index: 1 .. amc$max_path_name_size + 1,
      ring_attributes_specified: boolean,
      setfa_header: ^fmt$static_label_header,
      setfa_label_size: integer,
      sorted_attributes: ^amt$file_attributes,
      specified_file_structure_p: ^amt$file_structure,
      split_file_contents: amt$file_contents,
      split_file_structure: amt$file_structure,
      static_setfa_item: ^fmt$static_label_item,
      store_split_file_structure: boolean,
      str: ^string ( * ),
      warning_status: ost$status;

?? NEWTITLE := 'get_current_file_structure', EJECT ??

    PROCEDURE get_current_file_structure
      (VAR current_file_structure_p: ^string ( * ));

      VAR
        attribute: ^fmt$static_label_item,
        local_index: 1 .. amc$max_attribute + 1,
        local_setfa_sequence_p: ^SEQ ( * ),
        str: ^string ( * );

      current_file_structure_p := NIL;
      local_setfa_sequence_p := cycle_description^.static_setfa_entries;
      local_index := label_index + 1;
      WHILE local_index <= fmc$file_structure DO
        IF header^.attribute_present [local_index] THEN
          NEXT attribute: [local_index] IN local_setfa_sequence_p;
          IF attribute = NIL THEN
            RETURN;
          IFEND;
          IF local_index = fmc$file_processor THEN
            NEXT str: [attribute^.name_length] IN local_setfa_sequence_p;
          ELSEIF local_index = fmc$file_structure THEN
            NEXT str: [attribute^.name_length] IN local_setfa_sequence_p;
            current_file_structure_p := str;
          IFEND;
        IFEND;
        local_index := local_index + 1;
      WHILEND;

    PROCEND get_current_file_structure;

?? TITLE := 'process_attributes', EJECT ??

{ PURPOSE:
{   The purpose of this request is to store the specified dynamic attributes in
{   the cycle_description and calculate the size of the sequence needed to store
{   the specified static attributes.

    PROCEDURE process_attributes
      (    cycle_description: ^fmt$cycle_description;
       VAR attributes: ^amt$file_attributes;
       VAR setfa_label_size: integer;
       VAR ring_attributes_specified: boolean);

      PROCEDURE [INLINE] fsp$determine_static_attr_size
        (    key: amt$file_attribute_keys;
         VAR size: integer);

        CASE key OF
        = amc$block_type, amc$character_conversion, amc$clear_space, amc$file_organization, amc$forced_write,
              amc$internal_code, amc$label_type, amc$padding_character, amc$page_format, amc$record_type,
              amc$data_padding, amc$dynamic_home_block_space, amc$embedded_key, amc$index_padding,
              amc$key_type, amc$loading_factor, amc$logging_options =
          size := size + #SIZE (amt$attribute_source) + #SIZE (fmt$file_attribute_keys) +
                #SIZE (amt$block_type);

        = amc$file_contents =

{ Extra space might be needed if the specified file_contents is split into the original file_contents and
{ file_structure components for storage in the label.

          size := size + (2 * (#SIZE (amt$attribute_source) + #SIZE (fmt$file_attribute_keys) +
                1 + #SIZE (ost$name)));

        = amc$file_processor =
          size := size + #SIZE (amt$attribute_source) + #SIZE (fmt$file_attribute_keys) +
                1 + #SIZE (ost$name);

        = amc$file_structure =
          size := size + #SIZE (amt$attribute_source) + #SIZE (fmt$file_attribute_keys) +
                1 + #SIZE (ost$name);
          specified_file_structure_p := ^file_attributes^ [attribute_index].file_structure;

        = amc$line_number, amc$statement_identifier =
          size := size + #SIZE (amt$attribute_source) + #SIZE (fmt$file_attribute_keys) +
                #SIZE (amt$line_number);

        = amc$collate_table_name, amc$compression_procedure_name, amc$file_access_procedure,
              amc$hashing_procedure_name =
          size := size + #SIZE (amt$attribute_source) + #SIZE (fmt$file_attribute_keys) +
                3 + #SIZE (amt$entry_point_reference);

        = amc$log_residence =
          size := size + #SIZE (amt$attribute_source) + #SIZE (fmt$file_attribute_keys) +
                2 + #SIZE (amt$log_residence);

        = amc$user_info =
          size := size + #SIZE (amt$attribute_source) + #SIZE (fmt$file_attribute_keys) +
                1 + #SIZE (amt$user_info);

        ELSE
          size := size + #SIZE (amt$attribute_source) + #SIZE (fmt$file_attribute_keys) + #SIZE (integer);
        CASEND;

      PROCEND fsp$determine_static_attr_size;

      PROCEDURE [INLINE] initialize_dynamic_entries;

        IF cycle_description^.dynamic_setfa_entries = NIL THEN
          ALLOCATE cycle_description^.dynamic_setfa_entries IN osv$job_pageable_heap^;
          cycle_description^.dynamic_setfa_entries^ := default_dynamic_setfa_entries;
        IFEND;
      PROCEND initialize_dynamic_entries;

      VAR
        setfa_attribute_keys: file_attribute_keys;

      setfa_label_size := 0;
      setfa_attribute_keys := $file_attribute_keys [];
      ring_attributes_specified := FALSE;
      specified_file_structure_p := NIL;

      FOR attribute_index := UPPERBOUND (attributes^) DOWNTO 1 DO
        IF attributes^ [attribute_index].key IN setfa_attribute_keys THEN
          attributes^ [attribute_index].key := amc$null_attribute;
        ELSE
          setfa_attribute_keys := setfa_attribute_keys + $file_attribute_keys
                [attributes^ [attribute_index].key];
          CASE attributes^ [attribute_index].key OF
          = amc$access_mode =
            initialize_dynamic_entries;
            cycle_description^.dynamic_setfa_entries^.access_modes_specified := TRUE;
            #UNCHECKED_CONVERSION (attributes^ [attribute_index].access_mode,
                  cycle_description^.dynamic_setfa_entries^.access_modes);

          = amc$error_exit_name =
            initialize_dynamic_entries;
            cycle_description^.dynamic_setfa_entries^.error_exit_name_specified := TRUE;
            cycle_description^.dynamic_setfa_entries^.error_exit_name :=
                  attributes^ [attribute_index].error_exit_name;

          = amc$error_limit =
            initialize_dynamic_entries;
            cycle_description^.dynamic_setfa_entries^.error_limit_specified := TRUE;
            cycle_description^.dynamic_setfa_entries^.error_limit := attributes^ [attribute_index].
                  error_limit;

          = amc$label_exit_name =
            initialize_dynamic_entries;
            cycle_description^.dynamic_setfa_entries^.label_exit_name_specified := TRUE;
            cycle_description^.dynamic_setfa_entries^.label_exit_name :=
                  attributes^ [attribute_index].label_exit_name;

          = amc$message_control =
            initialize_dynamic_entries;
            cycle_description^.dynamic_setfa_entries^.message_control_specified := TRUE;
            cycle_description^.dynamic_setfa_entries^.message_control :=
                  attributes^ [attribute_index].message_control;

          = amc$open_position =
            initialize_dynamic_entries;
            cycle_description^.dynamic_setfa_entries^.open_position_specified := TRUE;
            cycle_description^.dynamic_setfa_entries^.open_position :=
                  attributes^ [attribute_index].open_position;

          = amc$ring_attributes =
            ring_attributes_specified := TRUE;

          ELSE

{ Calculate the size of the space needed in the sequence to store the static attributes specified by a SETFA.

            fsp$determine_static_attr_size (attributes^ [attribute_index].key, setfa_label_size);
          CASEND;
        IFEND;
      FOREND;

    PROCEND process_attributes;
?? OLDTITLE, EJECT ??
?? NEWTITLE := 'set_system_error_status', EJECT ??

    PROCEDURE set_system_error_status
      (    attribute: string ( * );
       VAR status: ost$status);

      VAR
        status_text: string (osc$max_string_size),
        text_length: integer;

      STRINGREP (status_text, text_length, 'Nexting of ', attribute,
            ' in SETFA_ENTRIES resulted in a NIL pointer in FMP$FILE_COMMAND');
      osp$set_status_abnormal (amc$access_method_id, fme$system_error, status_text (1, text_length), status);

    PROCEND set_system_error_status;
?? OLDTITLE ??
?? NEWTITLE := 'sort_setfa_entries', EJECT ??

{ PURPOSE:
{   The purpose of this request is to sort the file_attributes in ascending
{   order, by file_attribute keys.

    PROCEDURE sort_setfa_entries
      (    sorted_attributes: {input/output} ^amt$file_attributes);

      VAR
        current: integer,
        gap: integer,
        start: integer,
        swap: amt$file_item,
        swap_values: boolean;

{ Use shell sort technique.

      gap := UPPERBOUND (sorted_attributes^);
      WHILE gap > 1 DO
        gap := 2 * (gap DIV 4) + 1;
        FOR start := 1 TO (UPPERBOUND (sorted_attributes^) - gap) DO
          current := start;
          swap_values := TRUE;
          WHILE (current > 0) AND swap_values DO
            swap_values := file_label_key [sorted_attributes^ [current].key] >
                  file_label_key [sorted_attributes^ [current + gap].key];
            IF swap_values THEN
              swap := sorted_attributes^ [current];
              sorted_attributes^ [current] := sorted_attributes^ [current + gap];
              sorted_attributes^ [current + gap] := swap;
              current := current - gap;
            IFEND;
          WHILEND;
        FOREND;
      WHILEND;

    PROCEND sort_setfa_entries;
?? OLDTITLE ??
?? NEWTITLE := 'store_static_entry', EJECT ??

{ PURPOSE:
{   The purpose of this request is to store a static attribute into a temporary
{   label that has the same format as the file label.

    PROCEDURE store_static_entry
      (    key: fmt$file_attribute_keys;
           entry_kind: fmt$entry_kind;
       VAR status: ost$status);

      VAR
        conversion_status: ost$status,
        file_contents: amt$file_contents,
        file_structure: amt$file_structure,
        name_index: 1 .. osc$max_name_size + 1;

?? NEWTITLE := 'put_entry_point_reference', EJECT ??

      PROCEDURE [INLINE] put_entry_point_reference
        (    name: pmt$program_name;
             path: amt$file_reference);

        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF name <> osc$null_name THEN
          #SCAN (space_selector, name, name_index, ignore_found);
          static_setfa_item^.entry_point_name_length := name_index - 1;
          NEXT str: [static_setfa_item^.entry_point_name_length] IN new_setfa_label;
          str^ (1, static_setfa_item^.entry_point_name_length) := name;
        ELSE
          static_setfa_item^.entry_point_name_length := 1;
          NEXT str: [static_setfa_item^.entry_point_name_length] IN new_setfa_label;
          str^ (1, static_setfa_item^.entry_point_name_length) := ' ';
        IFEND;

        #SCAN (space_selector, path, path_index, ignore_found);
        static_setfa_item^.entry_point_path_length := path_index - 1;
        IF path_index > 1 THEN
          NEXT str: [static_setfa_item^.entry_point_path_length] IN new_setfa_label;
          str^ (1, static_setfa_item^.entry_point_path_length) := path;
        IFEND;

        IF key = label_index THEN { non-default value is currently stored }
          NEXT str: [item^.entry_point_name_length] IN cycle_description^.static_setfa_entries;
          IF str = NIL THEN
            set_system_error_status ('ENTRY_POINT NAME', status);
          ELSEIF item^.entry_point_path_length > 0 THEN
            NEXT str: [item^.entry_point_path_length] IN cycle_description^.static_setfa_entries;
            IF str = NIL THEN
              set_system_error_status ('ENTRY_POINT PATH', status);
            IFEND;
          IFEND;
        IFEND;

      PROCEND put_entry_point_reference;

?? TITLE := 'put_name', EJECT ??

      PROCEDURE [INLINE] put_name
        (    name: pmt$program_name);

        #SCAN (space_selector, name, name_index, ignore_found);
        static_setfa_item^.name_length := name_index - 1;
        NEXT str: [static_setfa_item^.name_length] IN new_setfa_label;
        str^ (1, static_setfa_item^.name_length) := name;
        IF key = label_index THEN
          NEXT str: [item^.name_length] IN cycle_description^.static_setfa_entries;
          IF str = NIL THEN
            set_system_error_status ('NAME', status);
          IFEND;
        IFEND;
      PROCEND put_name;

?? OLDTITLE, EJECT ??

      CASE key OF
      = fmc$block_type =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.block_type := sorted_attributes^ [attribute_index].block_type;
        ELSE
          static_setfa_item^.block_type := item^.block_type;
        IFEND;
      = fmc$character_conversion =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.character_conversion := sorted_attributes^ [attribute_index].
                character_conversion;
        ELSE
          static_setfa_item^.character_conversion := item^.character_conversion;
        IFEND;
      = fmc$clear_space =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.clear_space := sorted_attributes^ [attribute_index].clear_space;
        ELSE
          static_setfa_item^.clear_space := item^.clear_space;
        IFEND;
      = fmc$file_access_procedure =
        IF entry_kind = fmc$setfa_entry THEN
          put_entry_point_reference (sorted_attributes^ [attribute_index].file_access_procedure,
                osc$null_name);
        ELSE
          NEXT static_setfa_item: [key] IN new_setfa_label;
          static_setfa_item^.entry_point_name_length := item^.entry_point_name_length;
          NEXT str: [static_setfa_item^.entry_point_name_length] IN new_setfa_label;
          NEXT existing_str: [item^.entry_point_name_length] IN cycle_description^.static_setfa_entries;
          IF existing_str = NIL THEN
            set_system_error_status ('FILE_ACCESS_PROCEDURE entry_point_name', status);
            RETURN;
          IFEND;
          str^ (1, static_setfa_item^.entry_point_name_length) :=
                existing_str^ (1, item^.entry_point_name_length);
          static_setfa_item^.entry_point_path_length := item^.entry_point_path_length;
          IF static_setfa_item^.entry_point_path_length > 0 THEN
            NEXT str: [static_setfa_item^.entry_point_path_length] IN new_setfa_label;
            NEXT existing_str: [item^.entry_point_path_length] IN cycle_description^.static_setfa_entries;
            IF existing_str = NIL THEN
              set_system_error_status ('FILE_ACCESS_PROCEDURE entry_point_path', status);
              RETURN;
            IFEND;
            str^ (1, static_setfa_item^.entry_point_path_length) :=
                  existing_str^ (1, item^.entry_point_path_length);
          IFEND;
        IFEND;
      = fmc$file_contents =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN

{ For reasons of compatibility, the new keyword is split into the original file_contents and file_structure
{ components for storage in the setfa label; the single value of FC changes both the FC and FS components.
{ If an old value is specified for FC (legible, list, object, screen) or FS (data, library, form, etc.) and
{ previously specified values of FC and FS in the setfa label represent one of the new keywords, then these
{ values are treated as a unit by the new value of FC and/or FS; if the other parameter is not specified,
{ the corresponding label field is set to unknown.

          fsp$convert_to_old_contents (sorted_attributes^ [attribute_index].file_contents,
                split_file_contents, split_file_structure);
          IF (specified_file_structure_p = NIL) OR NOT (((split_file_contents = fsc$list) AND
                (specified_file_structure_p^ = fsc$unknown_contents)) OR
                ((sorted_attributes^ [attribute_index].file_contents = fsc$unknown_contents) AND
                (specified_file_structure_p^ = fsc$data))) THEN
            store_split_file_structure := (split_file_structure <> fsc$unknown_contents) OR
                  (split_file_contents = fsc$unknown_contents) OR (split_file_contents = fsc$source_map);
          IFEND;
          put_name (split_file_contents);
          IF key = label_index THEN

{ The original file_contents value was replaced and it needs to be kept around for later use in determining
{ if a previously defined file_structure needs to be replaced with UNKNOWN.

            previous_file_contents_p := str;
          IFEND;
          IF store_split_file_structure THEN

{ A keyword value was specified.  If the original values of file_contents and file_structure are not valid
{ keyword combinations, the original file_structure value will be replaced and a warning status returned.

            get_current_file_structure (current_file_structure_p);
            IF current_file_structure_p <> NIL THEN
              file_structure := current_file_structure_p^;
              IF previous_file_contents_p <> NIL THEN
                file_contents := previous_file_contents_p^;
                fsp$convert_file_contents (file_contents, file_structure, converted_file_contents,
                      conversion_status);
              IFEND;
              IF (NOT conversion_status.normal OR (previous_file_contents_p = NIL)) AND
                    (split_file_structure <> file_structure) THEN
                bap$set_file_reference_abnormal (file, fse$file_structure_replaced, '',
                      current_file_structure_p^, warning_status);
                osp$append_status_parameter (osc$status_parameter_delimiter, split_file_structure,
                      warning_status);
              IFEND;
              IF ((file_structure = fsc$data) AND (sorted_attributes^ [attribute_index].file_contents =
                    fsc$unknown_contents)) OR ((split_file_contents = fsc$list) AND
                    (converted_file_contents = fsc$unknown_contents)) THEN
                store_split_file_structure := FALSE;
                previous_file_contents_p := NIL;
              IFEND;
            IFEND;
          IFEND;
        ELSE
          NEXT existing_str: [item^.name_length] IN cycle_description^.static_setfa_entries;
          IF existing_str = NIL THEN
            set_system_error_status ('FILE_CONTENTS', status);
            RETURN;
          IFEND;

        /determine_file_contents/
          BEGIN
            IF specified_file_structure_p <> NIL THEN
              file_contents := existing_str^;
              file_structure := specified_file_structure_p^;
              fsp$convert_file_contents (file_contents, file_structure, converted_file_contents,
                    conversion_status);
              IF (NOT conversion_status.normal) AND (existing_str^ <> fsc$unknown_contents) THEN
                get_current_file_structure (current_file_structure_p);
                IF current_file_structure_p <> NIL THEN
                  file_structure := current_file_structure_p^;
                  fsp$convert_file_contents (file_contents, file_structure, converted_file_contents,
                        conversion_status);
                  IF conversion_status.normal THEN
                    static_setfa_item^.name_length := 7;
                    NEXT str: [static_setfa_item^.name_length] IN new_setfa_label;
                    str^ (1, static_setfa_item^.name_length) := fsc$unknown_contents;
                    bap$set_file_reference_abnormal (file, fse$file_contents_replaced, '',
                          converted_file_contents, warning_status);
                    EXIT /determine_file_contents/;
                  IFEND;
                IFEND;
              IFEND;
            IFEND;
            static_setfa_item^.name_length := item^.name_length;
            NEXT str: [static_setfa_item^.name_length] IN new_setfa_label;
            str^ (1, static_setfa_item^.name_length) := existing_str^ (1, item^.name_length);
          END /determine_file_contents/;
        IFEND;
      = fmc$file_limit =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].file_limit;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$file_organization =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.file_organization := sorted_attributes^ [attribute_index].file_organization;
        ELSE
          static_setfa_item^.file_organization := item^.file_organization;
        IFEND;
      = fmc$file_processor =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          put_name (sorted_attributes^ [attribute_index].file_processor);
        ELSE
          static_setfa_item^.name_length := item^.name_length;
          NEXT str: [static_setfa_item^.name_length] IN new_setfa_label;
          NEXT existing_str: [item^.name_length] IN cycle_description^.static_setfa_entries;
          IF existing_str = NIL THEN
            set_system_error_status ('FILE_PROCESSOR', status);
            RETURN;
          IFEND;
          str^ (1, static_setfa_item^.name_length) := existing_str^ (1, item^.name_length);
        IFEND;
      = fmc$file_structure =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF store_split_file_structure THEN
          put_name (split_file_structure);
          store_split_file_structure := FALSE;
          IF (specified_file_structure_p <> NIL) AND (specified_file_structure_p^ <> split_file_structure)
                THEN
            bap$set_file_reference_abnormal (file, fse$file_structure_discarded, '',
                  sorted_attributes^ [attribute_index].file_structure, warning_status);
          IFEND;
        ELSE
          IF entry_kind = fmc$setfa_entry THEN
            put_name (sorted_attributes^ [attribute_index].file_structure);
          ELSE
            NEXT existing_str: [item^.name_length] IN cycle_description^.static_setfa_entries;
            IF existing_str = NIL THEN
              set_system_error_status ('FILE_STRUCTURE', status);
              RETURN;
            IFEND;

          /determine_file_structure/
            BEGIN
              IF previous_file_contents_p <> NIL THEN { file_contents was specified }
                file_contents := previous_file_contents_p^;
                file_structure := existing_str^;
                fsp$convert_file_contents (file_contents, file_structure, converted_file_contents,
                      conversion_status);
                IF conversion_status.normal THEN
                  fsp$convert_file_contents (split_file_contents, file_structure, converted_file_contents,
                        conversion_status);
                  IF NOT conversion_status.normal THEN
                    static_setfa_item^.name_length := 7;
                    NEXT str: [static_setfa_item^.name_length] IN new_setfa_label;
                    str^ (1, static_setfa_item^.name_length) := fsc$unknown_contents;
                    EXIT /determine_file_structure/;
                  IFEND;
                IFEND;
              IFEND;
              static_setfa_item^.name_length := item^.name_length;
              NEXT str: [static_setfa_item^.name_length] IN new_setfa_label;
              str^ (1, static_setfa_item^.name_length) := existing_str^ (1, item^.name_length);
            END /determine_file_structure/;
          IFEND;
        IFEND;
      = fmc$forced_write =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.forced_write := sorted_attributes^ [attribute_index].forced_write;
        ELSE
          static_setfa_item^.forced_write := item^.forced_write;
        IFEND;
      = fmc$internal_code =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.internal_code := sorted_attributes^ [attribute_index].internal_code;
        ELSE
          static_setfa_item^.internal_code := item^.internal_code;
        IFEND;
      = fmc$label_type =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.label_type := sorted_attributes^ [attribute_index].label_type;
        ELSE
          static_setfa_item^.label_type := item^.label_type;
        IFEND;
      = fmc$line_number =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.line_number := sorted_attributes^ [attribute_index].line_number;
        ELSE
          static_setfa_item^.line_number := item^.line_number;
        IFEND;
      = fmc$max_block_length =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].max_block_length;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$max_record_length =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].max_record_length;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$min_block_length =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].min_block_length;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$min_record_length =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].min_record_length;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$padding_character =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.padding_character := sorted_attributes^ [attribute_index].padding_character;
        ELSE
          static_setfa_item^.padding_character := item^.padding_character;
        IFEND;
      = fmc$page_format =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.page_format := sorted_attributes^ [attribute_index].page_format;
        ELSE
          static_setfa_item^.page_format := item^.page_format;
        IFEND;
      = fmc$page_length =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].page_length;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$page_width =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].page_width;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$preset_value =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].preset_value;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$record_type =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.record_type := sorted_attributes^ [attribute_index].record_type;
        ELSE
          static_setfa_item^.record_type := item^.record_type;
        IFEND;
      = fmc$statement_identifier =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.statement_identifier := sorted_attributes^ [attribute_index].
                statement_identifier;
        ELSE
          static_setfa_item^.statement_identifier := item^.statement_identifier;
        IFEND;
      = fmc$user_info =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        static_setfa_item^.user_info_present := TRUE;
        NEXT str: [#SIZE (amt$user_info)] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          str^ (1, #SIZE (amt$user_info)) := sorted_attributes^ [attribute_index].user_info;
        ELSE
          NEXT existing_str: [#SIZE (amt$user_info)] IN cycle_description^.static_setfa_entries;
          IF existing_str = NIL THEN
            set_system_error_status ('USER_INFO', status);
            RETURN;
          IFEND;
          str^ (1, #SIZE (amt$user_info)) := existing_str^ (1, #SIZE (amt$user_info));
        IFEND;
      = fmc$vertical_print_density =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].vertical_print_density;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$average_record_length =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].average_record_length;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$collate_table_name =
        IF entry_kind = fmc$setfa_entry THEN
          put_entry_point_reference (sorted_attributes^ [attribute_index].collate_table_name, osc$null_name);
        ELSE
          NEXT static_setfa_item: [key] IN new_setfa_label;
          static_setfa_item^.entry_point_name_length := item^.entry_point_name_length;
          NEXT str: [static_setfa_item^.entry_point_name_length] IN new_setfa_label;
          NEXT existing_str: [item^.entry_point_name_length] IN cycle_description^.static_setfa_entries;
          IF existing_str = NIL THEN
            set_system_error_status ('COLLATE_TABLE_NAME entry_point_name ', status);
            RETURN;
          IFEND;
          str^ (1, static_setfa_item^.entry_point_name_length) :=
                existing_str^ (1, item^.entry_point_name_length);
          static_setfa_item^.entry_point_path_length := item^.entry_point_path_length;
          IF static_setfa_item^.entry_point_path_length > 0 THEN
            NEXT str: [static_setfa_item^.entry_point_path_length] IN new_setfa_label;
            NEXT existing_str: [item^.entry_point_path_length] IN cycle_description^.static_setfa_entries;
            IF existing_str = NIL THEN
              set_system_error_status ('COLLATE_TABLE_NAME entry_point_path', status);
              RETURN;
            IFEND;
            str^ (1, static_setfa_item^.entry_point_path_length) :=
                  existing_str^ (1, item^.entry_point_path_length);
          IFEND;
        IFEND;
      = fmc$compression_procedure_name =
        IF entry_kind = fmc$setfa_entry THEN
          IF sorted_attributes^ [attribute_index].compression_procedure_name <> NIL THEN
            put_entry_point_reference (sorted_attributes^ [attribute_index].compression_procedure_name^.name,
                  sorted_attributes^ [attribute_index].compression_procedure_name^.object_library);
          IFEND;
        ELSE
          NEXT static_setfa_item: [key] IN new_setfa_label;
          static_setfa_item^.entry_point_name_length := item^.entry_point_name_length;
          NEXT str: [static_setfa_item^.entry_point_name_length] IN new_setfa_label;
          NEXT existing_str: [item^.entry_point_name_length] IN cycle_description^.static_setfa_entries;
          IF existing_str = NIL THEN
            set_system_error_status ('COMPRESSION_PROCEDURE_NAME entry_point_name', status);
            RETURN;
          IFEND;
          str^ (1, static_setfa_item^.entry_point_name_length) :=
                existing_str^ (1, item^.entry_point_name_length);
          static_setfa_item^.entry_point_path_length := item^.entry_point_path_length;
          IF static_setfa_item^.entry_point_path_length > 0 THEN
            NEXT str: [static_setfa_item^.entry_point_path_length] IN new_setfa_label;
            NEXT existing_str: [item^.entry_point_path_length] IN cycle_description^.static_setfa_entries;
            IF existing_str = NIL THEN
              set_system_error_status ('COMPRESSION_PROCEDURE_NAME entry_point_path', status);
              RETURN;
            IFEND;
            str^ (1, static_setfa_item^.entry_point_path_length) :=
                  existing_str^ (1, item^.entry_point_path_length);
          IFEND;
        IFEND;
      = fmc$data_padding =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.data_padding := sorted_attributes^ [attribute_index].data_padding;
        ELSE
          static_setfa_item^.data_padding := item^.data_padding;
        IFEND;
      = fmc$dynamic_home_block_space =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.dynamic_home_block_space := sorted_attributes^ [attribute_index].
                dynamic_home_block_space;
        ELSE
          static_setfa_item^.dynamic_home_block_space := item^.dynamic_home_block_space;
        IFEND;
      = fmc$embedded_key =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.embedded_key := sorted_attributes^ [attribute_index].embedded_key;
        ELSE
          static_setfa_item^.embedded_key := item^.embedded_key;
        IFEND;
      = fmc$estimated_record_count =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].estimated_record_count;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$hashing_procedure_name =
        IF entry_kind = fmc$setfa_entry THEN
          IF sorted_attributes^ [attribute_index].hashing_procedure_name <> NIL THEN
            put_entry_point_reference (sorted_attributes^ [attribute_index].hashing_procedure_name^.name,
                  sorted_attributes^ [attribute_index].hashing_procedure_name^.object_library);
          IFEND;
        ELSE
          NEXT static_setfa_item: [key] IN new_setfa_label;
          static_setfa_item^.entry_point_name_length := item^.entry_point_name_length;
          NEXT str: [static_setfa_item^.entry_point_name_length] IN new_setfa_label;
          NEXT existing_str: [item^.entry_point_name_length] IN cycle_description^.static_setfa_entries;
          IF existing_str = NIL THEN
            set_system_error_status ('HASHING_PROCEDURE_NAME entry_point_name', status);
            RETURN;
          IFEND;
          str^ (1, static_setfa_item^.entry_point_name_length) :=
                existing_str^ (1, item^.entry_point_name_length);
          static_setfa_item^.entry_point_path_length := item^.entry_point_path_length;
          IF static_setfa_item^.entry_point_path_length > 0 THEN
            NEXT str: [static_setfa_item^.entry_point_path_length] IN new_setfa_label;
            NEXT existing_str: [item^.entry_point_path_length] IN cycle_description^.static_setfa_entries;
            IF existing_str = NIL THEN
              set_system_error_status ('HASHING_PROCEDURE_NAME entry_point_path', status);
              RETURN;
            IFEND;
            str^ (1, static_setfa_item^.entry_point_path_length) :=
                  existing_str^ (1, item^.entry_point_path_length);
          IFEND;
        IFEND;
      = fmc$index_levels =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].index_levels;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$index_padding =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.index_padding := sorted_attributes^ [attribute_index].index_padding;
        ELSE
          static_setfa_item^.index_padding := item^.index_padding;
        IFEND;
      = fmc$initial_home_block_count =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].initial_home_block_count;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$key_length =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].key_length;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$key_position =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].key_position;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$key_type =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.key_type := sorted_attributes^ [attribute_index].key_type;
        ELSE
          static_setfa_item^.key_type := item^.key_type;
        IFEND;
      = fmc$loading_factor =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.loading_factor := sorted_attributes^ [attribute_index].loading_factor;
        ELSE
          static_setfa_item^.loading_factor := item^.loading_factor;
        IFEND;
      = fmc$lock_expiration_time =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].lock_expiration_time;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$logging_options =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.logging_options := sorted_attributes^ [attribute_index].logging_options;
        ELSE
          static_setfa_item^.logging_options := item^.logging_options;
        IFEND;
      = fmc$log_residence =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          IF sorted_attributes^ [attribute_index].log_residence <> NIL THEN
            #SCAN (space_selector, sorted_attributes^ [attribute_index].log_residence^, path_index,
                  ignore_found);
            static_setfa_item^.path_length := path_index - 1;
            NEXT str: [static_setfa_item^.path_length] IN new_setfa_label;
            str^ (1, static_setfa_item^.path_length) := sorted_attributes^ [attribute_index].log_residence^;
          IFEND;
        ELSE
          static_setfa_item^.path_length := item^.path_length;
          NEXT str: [static_setfa_item^.path_length] IN new_setfa_label;
          NEXT existing_str: [item^.path_length] IN cycle_description^.static_setfa_entries;
          IF existing_str = NIL THEN
            set_system_error_status ('LOG_RESIDENCE path', status);
            RETURN;
          IFEND;
          str^ (1, static_setfa_item^.path_length) := existing_str^ (1, item^.path_length);
        IFEND;
      = fmc$record_limit =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].record_limit;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      = fmc$records_per_block =
        NEXT static_setfa_item: [key] IN new_setfa_label;
        IF entry_kind = fmc$setfa_entry THEN
          static_setfa_item^.integer_value := sorted_attributes^ [attribute_index].records_per_block;
        ELSE
          static_setfa_item^.integer_value := item^.integer_value;
        IFEND;
      ELSE
        RETURN;
      CASEND;
      IF status.normal THEN
        setfa_header^.attribute_present [key] := TRUE;
        setfa_header^.highest_attribute_present := key;
        static_setfa_item^.source := amc$file_command;
      IFEND;

    PROCEND store_static_entry;
?? OLDTITLE, EJECT ??

    status.normal := TRUE;
    warning_status.normal := TRUE;

    IF file_attributes <> NIL THEN
      fmp$evaluate_path (file, $bat$process_pt_work_list [bac$resolve_path, bac$resolve_to_catalog,
            bac$record_path, bac$create_cycle_description, bac$return_cycle_description],
            ignore_evaluated_file_reference, cycle_description, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

    /process_setfa_command/
      BEGIN
        PUSH sorted_attributes: [1 .. UPPERBOUND (file_attributes^)];
        sorted_attributes^ := file_attributes^;
        process_attributes (cycle_description, sorted_attributes, setfa_label_size,
              ring_attributes_specified);
        IF (cycle_description^.attached_file AND cycle_description^.system_file_label.
              file_previously_opened AND (cycle_description^.device_class <> rmc$magnetic_tape_device)) OR
              ((setfa_label_size = 0) AND NOT ring_attributes_specified) THEN
          EXIT /process_setfa_command/;
        IFEND;

        sort_setfa_entries (sorted_attributes);

        store_split_file_structure := FALSE;

        IF cycle_description^.static_setfa_entries = NIL THEN
          setfa_label_size := setfa_label_size + #SIZE (fmt$static_label_header);
          PUSH new_setfa_label: [[REP setfa_label_size OF cell]];
          NEXT setfa_header IN new_setfa_label;
          setfa_header^ := fmv$static_label_header;
          setfa_header^.file_previously_opened := FALSE;
          attribute_index := LOWERBOUND (sorted_attributes^);
        ELSE
          setfa_label_size := setfa_label_size + #SIZE (cycle_description^.static_setfa_entries^);
          PUSH new_setfa_label: [[REP setfa_label_size OF cell]];
          NEXT setfa_header IN new_setfa_label;
          setfa_header^ := fmv$static_label_header;
          setfa_header^.file_previously_opened := FALSE;

          RESET cycle_description^.static_setfa_entries;
          NEXT header IN cycle_description^.static_setfa_entries;
          IF header = NIL THEN
            set_system_error_status ('HEADER', status);
            EXIT /process_setfa_command/;
          IFEND;

          previous_file_contents_p := NIL;
          attribute_index := 1;
          FOR label_index := LOWERBOUND (header^.attribute_present) TO header^.highest_attribute_present DO
            IF header^.attribute_present [label_index] THEN
              NEXT item: [label_index] IN cycle_description^.static_setfa_entries;
              IF item = NIL THEN
                set_system_error_status ('ITEM', status);
                EXIT /process_setfa_command/;
              IFEND;
              label_item_replaced := FALSE;
              WHILE (attribute_index <= UPPERBOUND (sorted_attributes^)) AND
                    (file_label_key [sorted_attributes^ [attribute_index].key] <= label_index) DO
                IF store_split_file_structure AND (specified_file_structure_p = NIL) AND
                      (file_label_key [sorted_attributes^ [attribute_index].key] > fmc$file_structure) THEN
                  store_static_entry (fmc$file_structure, fmc$setfa_entry, status);
                  IF NOT status.normal THEN
                    EXIT /process_setfa_command/;
                  IFEND;
                IFEND;
                store_static_entry (file_label_key [sorted_attributes^ [attribute_index].key],
                      fmc$setfa_entry, status);
                IF NOT status.normal THEN
                  EXIT /process_setfa_command/;
                IFEND;
                label_item_replaced := file_label_key [sorted_attributes^ [attribute_index].key] =
                      label_index;
                attribute_index := attribute_index + 1;
              WHILEND;

              IF store_split_file_structure AND (specified_file_structure_p = NIL) AND
                    (label_index > fmc$file_structure) THEN
                store_static_entry (fmc$file_structure, fmc$setfa_entry, status);
                IF NOT status.normal THEN
                  EXIT /process_setfa_command/;
                IFEND;
              IFEND;

              IF NOT label_item_replaced THEN
                store_static_entry (label_index, fmc$label_entry, status);
                IF NOT status.normal THEN
                  EXIT /process_setfa_command/;
                IFEND;
              IFEND;
            IFEND;
          FOREND;

        IFEND;

{ The variable label_index should be initialized to a value beyond the scope of the current valid
{ file_attribute keys so that the check for "key = label_index" in PUT_NAME and PUT_ENTRY_POINT_REFERENCE
{ in STORE_STATIC_ENTRY is always false.

        label_index := amc$max_attribute;
        WHILE (attribute_index <= UPPERBOUND (sorted_attributes^)) AND
              (file_label_key [sorted_attributes^ [attribute_index].key] < amc$max_attribute) DO
          IF store_split_file_structure AND (specified_file_structure_p = NIL) AND
                (file_label_key [sorted_attributes^ [attribute_index].key] > fmc$file_structure) THEN
            store_static_entry (fmc$file_structure, fmc$setfa_entry, status);
            IF NOT status.normal THEN
              EXIT /process_setfa_command/;
            IFEND;
          IFEND;
          store_static_entry (file_label_key [sorted_attributes^ [attribute_index].key],
                fmc$setfa_entry, status);
          IF NOT status.normal THEN
            EXIT /process_setfa_command/;
          IFEND;
          attribute_index := attribute_index + 1;
        WHILEND;

{ The following IF statement is necessary for the case where file_contents is the only attribute
{ specified or no attributes with keys greater than the file_structure key is specified.

        IF store_split_file_structure THEN
          store_static_entry (fmc$file_structure, fmc$setfa_entry, status);
          IF NOT status.normal THEN
            EXIT /process_setfa_command/;
          IFEND;
        IFEND;

        setfa_label_size := i#current_sequence_position (new_setfa_label);
        ALLOCATE cycle_description^.static_setfa_entries: [[REP setfa_label_size OF cell]] IN
              osv$job_pageable_heap^;
        RESET new_setfa_label;
        RESET cycle_description^.static_setfa_entries;
        i#move (new_setfa_label, cycle_description^.static_setfa_entries, setfa_label_size);

        IF status.normal AND NOT warning_status.normal THEN
          status := warning_status;
        IFEND;

      END /process_setfa_command/;
      fmp$unlock_path_table;
    IFEND; { file_attributes <> NIL }

  PROCEND fmp$file_command;

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

  PROCEDURE [XDCL, #GATE] fmp$get_setfa_dynamic_attrs
    (    file: fst$file_reference;
     VAR attached_permanent_file: boolean;
     VAR attached_share_modes: fst$file_access_options;
     VAR setfa_specified: boolean;
     VAR dynamic_attributes: fst$setfa_attachment_options;
     VAR status: ost$status);

    CONST
      command_file_reference_allowed = TRUE;

    VAR
      cycle_description: ^fmt$cycle_description,
      evaluated_file_reference: fst$evaluated_file_reference,
      index: integer;

    status.normal := TRUE;
    attached_permanent_file := FALSE;
    attached_share_modes := $fst$file_access_options [];
    setfa_specified := FALSE;
    dynamic_attributes := default_dynamic_setfa_entries;

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

    IF cycle_description^.attached_file AND (cycle_description^.device_class = rmc$mass_storage_device) AND
          cycle_description^.permanent_file THEN
      attached_permanent_file := TRUE;
      attached_share_modes := cycle_description^.attached_share_modes;
    IFEND;

    IF cycle_description^.dynamic_setfa_entries <> NIL THEN
      setfa_specified := TRUE;
      dynamic_attributes := cycle_description^.dynamic_setfa_entries^;
    IFEND;

    fmp$unlock_path_table;

  PROCEND fmp$get_setfa_dynamic_attrs;

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

{ PURPOSE:
{   This procedure merges attributes that were specified on a SETFA command or
{   the bap$file_command program_interface, with the label of a file that has
{   not been previously opened.
{
{ DESIGN:
{   NEXT through the sequence containing the static attributes specified on
{   a SETFA and merge the values and sources into the file label.
{
{ NOTE:
{   This procedure assumes that it will be called only when
{   there are static_setfa_entries to be merged, implying that the
{   "static_setfa_entries" parameter should never be NIL.

  PROCEDURE [XDCL, #GATE] fmp$merge_setfa_entries
    (    static_setfa_entries: ^SEQ ( * );
         object_p: {input/output} ^fst$goi_object;
     VAR object_information_p: {input/output} ^SEQ ( * );
     VAR status: ost$status);

    VAR
      entry_point_path: ^string ( * <= amc$max_path_name_size),
      final_attribute: 0 .. amc$max_attribute,
      index: fmt$file_attribute_keys,
      item: ^fmt$static_label_item,
      label_header: ^fmt$static_label_header,
      label_size: integer,
      local_file_label: ^SEQ ( * ),
      local_setfa_entries: ^SEQ ( * ),
      max_label_size: integer,
      merged_label: ^SEQ ( * ),
      merged_label_header: ^fmt$static_label_header,
      merged_label_item: ^fmt$static_label_item,
      merged_label_str: ^string ( * <= amc$max_path_name_size),
      str: ^string ( * <= amc$max_path_name_size),
      setfa_header: ^fmt$static_label_header;

?? NEWTITLE := 'set_system_error_status', EJECT ??

    PROCEDURE set_system_error_status
      (    text: string ( * );
       VAR status: ost$status);

      VAR
        status_text: string (osc$max_string_size),
        text_length: integer;

      STRINGREP (status_text, text_length, 'Nexting of ', text,
            ' in SETFA_ENTRIES resulted in a NIL pointer in FMP$MERGE_SETFA_ENTRIES');
      osp$set_status_abnormal (amc$access_method_id, fme$system_error, status_text (1, text_length), status);

    PROCEND set_system_error_status;
?? OLDTITLE ??
?? NEWTITLE := 'set_damaged_attribute_status', EJECT ??

    PROCEDURE set_damaged_attribute_status
      (    text: string ( * );
       VAR status: ost$status);

      VAR
        status_text: string (osc$max_string_size),
        text_length: integer;

      STRINGREP (status_text, text_length, 'Nexting of ', text,
            ' in LABEL resulted in a NIL pointer in FMP$MERGE_SETFA_ENTRIES');
      osp$set_status_abnormal (amc$access_method_id, ame$damaged_file_attributes,
            status_text (1, text_length), status);

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

    IF object_p <> NIL THEN
      IF object_p^.file_label = NIL THEN

{ It is assumed that this procedure would never be called for a temporary file
{ that has been previously opened, and that permanent files always have a label
{ if they have been opened.

        label_size := #SIZE (static_setfa_entries^);
        NEXT object_p^.file_label: [[REP label_size OF cell]] IN object_information_p;
        IF object_p^.file_label = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          RETURN;
        IFEND;
        i#move (static_setfa_entries, object_p^.file_label, label_size);
      ELSE
        local_file_label := object_p^.file_label;
        RESET local_file_label;
        NEXT label_header IN local_file_label;
        IF label_header = NIL THEN
          set_damaged_attribute_status ('LABEL_HEADER', status);
          RETURN;
        IFEND;
        IF label_header^.file_previously_opened THEN
          RETURN;
        IFEND;

        max_label_size := #SIZE (local_file_label^) + #SIZE (static_setfa_entries^) -
              #SIZE (fmt$static_label_header);
        PUSH merged_label: [[REP max_label_size OF cell]];
        RESET merged_label;
        NEXT merged_label_header IN merged_label;
        merged_label_header^ := fmv$static_label_header;
        merged_label_header^.file_previously_opened := FALSE;

        local_setfa_entries := static_setfa_entries;
        RESET local_setfa_entries;
        NEXT setfa_header IN local_setfa_entries;
        IF setfa_header = NIL THEN
          set_system_error_status ('HEADER', status);
          RETURN;
        IFEND;
        IF label_header^.highest_attribute_present <= setfa_header^.highest_attribute_present THEN
          final_attribute := setfa_header^.highest_attribute_present;
        ELSE
          final_attribute := label_header^.highest_attribute_present;
        IFEND;
        FOR index := fmc$average_record_length TO final_attribute DO
          CASE index OF
          = fmc$file_contents, fmc$file_processor, fmc$file_structure =
            IF label_header^.attribute_present [index] THEN
              NEXT item: [index] IN local_file_label;
              IF item = NIL THEN
                set_damaged_attribute_status ('NAME ITEM', status);
                RETURN;
              IFEND;

              NEXT str: [item^.name_length] IN local_file_label;
              IF str = NIL THEN
                set_damaged_attribute_status ('NAME string', status);
                RETURN;
              IFEND;
            IFEND;

            IF setfa_header^.attribute_present [index] THEN
              NEXT item: [index] IN local_setfa_entries;
              IF item = NIL THEN
                set_system_error_status ('NAME ITEM', status);
                RETURN;
              IFEND;
              NEXT merged_label_item: [index] IN merged_label;
              i#move (item, merged_label_item, #SIZE (merged_label_item^));
              NEXT str: [item^.name_length] IN local_setfa_entries;
              IF str = NIL THEN
                set_system_error_status ('NAME string', status);
                RETURN;
              IFEND;
              NEXT merged_label_str: [merged_label_item^.name_length] IN merged_label;
              merged_label_str^ := str^;
              merged_label_header^.attribute_present [index] := TRUE;
              merged_label_header^.highest_attribute_present := index;
            ELSEIF label_header^.attribute_present [index] THEN
              NEXT merged_label_item: [index] IN merged_label;
              i#move (item, merged_label_item, #SIZE (merged_label_item^));
              NEXT merged_label_str: [merged_label_item^.name_length] IN merged_label;
              merged_label_str^ := str^;
              merged_label_header^.attribute_present [index] := TRUE;
              merged_label_header^.highest_attribute_present := index;
            IFEND;

          = fmc$compression_procedure_name, fmc$hashing_procedure_name, fmc$file_access_procedure,
                fmc$collate_table_name =
            IF label_header^.attribute_present [index] THEN
              NEXT item: [index] IN local_file_label;
              IF item = NIL THEN
                set_damaged_attribute_status ('ENTRY_POINT ITEM', status);
                RETURN;
              IFEND;

              NEXT str: [item^.entry_point_name_length] IN local_file_label;
              IF str = NIL THEN
                set_damaged_attribute_status ('ENTRY_POINT NAME', status);
                RETURN;
              IFEND;
              IF item^.entry_point_path_length > 0 THEN
                NEXT entry_point_path: [item^.entry_point_path_length] IN local_file_label;
                IF entry_point_path = NIL THEN
                  set_damaged_attribute_status ('ENTRY_POINT PATH', status);
                  RETURN;
                IFEND;
              IFEND;
            IFEND;

            IF setfa_header^.attribute_present [index] THEN
              NEXT item: [index] IN local_setfa_entries;
              IF item = NIL THEN
                set_system_error_status ('ENTRY_POINT ITEM', status);
                RETURN;
              IFEND;
              NEXT merged_label_item: [index] IN merged_label;
              i#move (item, merged_label_item, #SIZE (merged_label_item^));
              NEXT str: [item^.entry_point_name_length] IN local_setfa_entries;
              IF str = NIL THEN
                set_system_error_status ('ENTRY_POINT NAME', status);
                RETURN;
              IFEND;
              NEXT merged_label_str: [merged_label_item^.entry_point_name_length] IN merged_label;
              merged_label_str^ := str^;
              IF merged_label_item^.entry_point_path_length > 0 THEN
                NEXT entry_point_path: [item^.entry_point_path_length] IN local_setfa_entries;
                IF entry_point_path = NIL THEN
                  set_system_error_status ('ENTRY_POINT PATH', status);
                  RETURN;
                IFEND;
                NEXT merged_label_str: [merged_label_item^.entry_point_path_length] IN merged_label;
                merged_label_str^ := entry_point_path^;
              IFEND;
              merged_label_header^.attribute_present [index] := TRUE;
              merged_label_header^.highest_attribute_present := index;
            ELSEIF label_header^.attribute_present [index] THEN
              NEXT merged_label_item: [index] IN merged_label;
              i#move (item, merged_label_item, #SIZE (merged_label_item^));
              NEXT merged_label_str: [merged_label_item^.entry_point_name_length] IN merged_label;
              merged_label_str^ := str^;
              IF merged_label_item^.entry_point_path_length > 0 THEN
                NEXT merged_label_str: [merged_label_item^.entry_point_path_length] IN merged_label;
                merged_label_str^ := entry_point_path^;
              IFEND;
              merged_label_header^.attribute_present [index] := TRUE;
              merged_label_header^.highest_attribute_present := index;
            IFEND;

          = fmc$user_info =
            IF label_header^.attribute_present [index] THEN
              NEXT item: [index] IN local_file_label;
              IF item = NIL THEN
                set_damaged_attribute_status ('USER_INFO ITEM', status);
                RETURN;
              IFEND;

              IF item^.user_info_present THEN
                NEXT str: [#SIZE (amt$user_info)] IN local_file_label;
                IF str = NIL THEN
                  set_damaged_attribute_status ('USER_INFO STRING', status);
                  RETURN;
                IFEND;
              IFEND;
            IFEND;

            IF setfa_header^.attribute_present [index] THEN
              NEXT item: [index] IN local_setfa_entries;
              IF item = NIL THEN
                set_system_error_status ('USER_INFO ITEM', status);
                RETURN;
              IFEND;
              NEXT merged_label_item: [index] IN merged_label;
              i#move (item, merged_label_item, #SIZE (merged_label_item^));
              IF item^.user_info_present THEN
                NEXT str: [#SIZE (amt$user_info)] IN local_setfa_entries;
                IF str = NIL THEN
                  set_system_error_status ('USER_INFO STRING', status);
                  RETURN;
                IFEND;
                NEXT merged_label_str: [#SIZE (amt$user_info)] IN merged_label;
                merged_label_str^ := str^;
              IFEND;
              merged_label_header^.attribute_present [index] := TRUE;
              merged_label_header^.highest_attribute_present := index;
            ELSEIF label_header^.attribute_present [index] THEN
              NEXT merged_label_item: [index] IN merged_label;
              i#move (item, merged_label_item, #SIZE (merged_label_item^));
              IF item^.user_info_present THEN
                NEXT merged_label_str: [#SIZE (amt$user_info)] IN merged_label;
                merged_label_str^ := str^;
              IFEND;
              merged_label_header^.attribute_present [index] := TRUE;
              merged_label_header^.highest_attribute_present := index;
            IFEND;

          = fmc$log_residence =
            IF label_header^.attribute_present [index] THEN
              NEXT item: [index] IN local_file_label;
              IF item = NIL THEN
                set_damaged_attribute_status ('LOG_RESIDENCE ITEM', status);
                RETURN;
              IFEND;

              NEXT str: [item^.path_length] IN local_file_label;
              IF str = NIL THEN
                set_damaged_attribute_status ('LOG_RESIDENCE STRING', status);
                RETURN;
              IFEND;
            IFEND;

            IF setfa_header^.attribute_present [index] THEN
              NEXT item: [index] IN local_setfa_entries;
              IF item = NIL THEN
                set_system_error_status ('LOG_RESIDENCE ITEM', status);
                RETURN;
              IFEND;
              NEXT merged_label_item: [index] IN merged_label;
              i#move (item, merged_label_item, #SIZE (merged_label_item^));
              NEXT str: [item^.path_length] IN local_setfa_entries;
              IF str = NIL THEN
                set_system_error_status ('LOG_RESIDENCE STRING', status);
                RETURN;
              IFEND;
              NEXT merged_label_str: [merged_label_item^.path_length] IN merged_label;
              merged_label_str^ := str^;
              merged_label_header^.attribute_present [index] := TRUE;
              merged_label_header^.highest_attribute_present := index;
            ELSEIF label_header^.attribute_present [index] THEN
              NEXT merged_label_item: [index] IN merged_label;
              i#move (item, merged_label_item, #SIZE (merged_label_item^));
              NEXT merged_label_str: [merged_label_item^.path_length] IN merged_label;
              merged_label_str^ := str^;
              merged_label_header^.attribute_present [index] := TRUE;
              merged_label_header^.highest_attribute_present := index;
            IFEND;

          ELSE
            IF label_header^.attribute_present [index] THEN
              NEXT item: [index] IN local_file_label;
              IF item = NIL THEN
                set_damaged_attribute_status ('ITEM', status);
                RETURN;
              IFEND;
            IFEND;
            IF setfa_header^.attribute_present [index] THEN
              NEXT item: [index] IN local_setfa_entries;
              IF item = NIL THEN
                set_system_error_status ('ITEM', status);
                RETURN;
              IFEND;
              NEXT merged_label_item: [index] IN merged_label;
              i#move (item, merged_label_item, #SIZE (merged_label_item^));
              merged_label_header^.attribute_present [index] := TRUE;
              merged_label_header^.highest_attribute_present := index;
            ELSEIF label_header^.attribute_present [index] THEN
              NEXT merged_label_item: [index] IN merged_label;
              i#move (item, merged_label_item, #SIZE (merged_label_item^));
              merged_label_header^.attribute_present [index] := TRUE;
              merged_label_header^.highest_attribute_present := index;
            IFEND;

          CASEND;
        FOREND;

        label_size := i#current_sequence_position (merged_label);
        NEXT object_p^.file_label: [[REP label_size OF cell]] IN object_information_p;
        IF object_p^.file_label = NIL THEN
          osp$set_status_condition (pfe$info_full, status);
          RETURN;
        IFEND;
        i#move (merged_label, object_p^.file_label, label_size);
      IFEND; { object_p^.file_label = NIL }
    IFEND; { object_p <> NIL }

  PROCEND fmp$merge_setfa_entries;
MODEND fmm$setfa_processing;
