MODULE fsm#expand_file_label;
?? RIGHT := 90 ??

{FSP#EXPAND_FILE_LABEL   returns requested file attributes from a file label

?? NEWTITLE := 'Global Declarations Referenced By This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc fmt#file_attribute_keys_set

*copyc fmc$unique_label_id
*copyc ame$attribute_validation_errors
*copyc amt$file_reference
*copyc amt$path_name
*copyc bat$static_label_attributes
*copyc fmt$file_attribute_keys
*copyc fmt$static_label_header
*copyc fmt$static_label_item
*copyc ost$halfword
*copyc ost$name_reference
?? POP ??
*copyc fip#move

*copyc fsp$convert_to_old_contents
*copyc osp$set_status_abnormal
*copyc pmp$load

?? TITLE := '[xdcl] FSP#EXPAND_FILE_LABEL', EJECT ??

  PROCEDURE [XDCL] fsp#expand_file_label
    (    file_label_p: ^SEQ ( * );
         requested_label_atts: fmt#file_attribute_keys_set;
     VAR label_atts: bat$static_label_attributes;
     VAR file_previously_opened: boolean;
     VAR status: ost$status);

{Return the REQUESTED_LABEL_ATTRIBUTES in FILE_LABEL.
{
{The FILE_LABEL sequence is next-ed for each existing attribute. If the
{attribute is a requested one, it is set into LABEL_ATTS.  This process
{is repeated until all requested file attributes have been found.
{
{NOTES
{ . For faster execution, no ELSE is used in the CASE statements involving
{   the FMT$FILE_ATTRIBUTE_KEYS selector.  This means if a new file attribute
{   key is added, this code must be updated. Even an ELSE would not get away
{   from this problem should a new file attribute key be added, as there would
{   still be no way of knowing how many bytes to skip in the label for the
{   new attribute.

    VAR {!?Kludge so can preset string pointers to non-nil value.?!
      null_string: [READ] string (0) := '';

    VAR
      attribute_key: fmt$file_attribute_keys,
      header_p: ^fmt$static_label_header,
      label_item_p: ^fmt$static_label_item,
      name_p: ^ost$name_reference,
      path_p: ^amt$file_reference,
      present_label_atts_n: integer,
      reassign_file_contents: boolean,
      split_file_contents: amt$file_contents,
      split_file_structure: amt$file_structure,
      static_label_p: ^SEQ ( * );

?? NEWTITLE := 'GET_ENTRY_POINT_REFERENCE', EJECT ??

    PROCEDURE [INLINE] get_entry_point_reference
      (VAR name_p: ^ost$name_reference;
       VAR path_p: ^amt$file_reference);

      NEXT name_p: [label_item_p^.entry_point_name_length] IN static_label_p;
      IF (label_item_p <> NIL) AND (label_item_p^.entry_point_path_length > 0) THEN
        NEXT path_p: [label_item_p^.entry_point_path_length] IN static_label_p;
      IFEND;

    PROCEND get_entry_point_reference;
?? TITLE := 'GET_NAME', EJECT ??

    PROCEDURE [INLINE] get_name
      (VAR name_p: ^ost$name_reference);

      IF (label_item_p <> NIL) THEN
        NEXT name_p: [label_item_p^.name_length] IN static_label_p;
      IFEND;

    PROCEND get_name;
?? TITLE := 'SET_RETRIEVABLE_LABEL_ATTS', EJECT ??

    PROCEDURE [INLINE] set_retrievable_label_atts
      (    requested_label_atts: fmt#file_attribute_keys_set;
       VAR present_label_atts_n: integer);

{Return how many requested label attributes are in this file label.
{Ring attributes does not count, as returned outside of file label.

      present_label_atts_n := 0;
      FOR attribute_key := LOWERBOUND (header_p^.attribute_present) TO header_p^.
            highest_attribute_present DO
        IF (header_p^.attribute_present [attribute_key]) AND
              (attribute_key IN requested_label_atts) THEN
          present_label_atts_n := present_label_atts_n + 1;
        IFEND;
      FOREND;
      IF (fmc$ring_attributes IN requested_label_atts) THEN
        present_label_atts_n := present_label_atts_n - 1;
      IFEND;

    PROCEND set_retrievable_label_atts;
?? TITLE := 'SET_STATUS_DAMAGED_ATTRIBUTES', EJECT ??

    PROCEDURE set_status_damaged_attributes
      (    attribute_index: 1 .. fmc$highest_current_attribute + 5;
       VAR status: ost$status);

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

      STRINGREP (status_text, text_length, 'Nexting of attribute # ', attribute_index,
            ' in LABEL resulted in a NIL pointer in P#EXPAND_FILE_LABEL');
      osp$set_status_abnormal (amc$access_method_id, ame$damaged_file_attributes,
            status_text (1, text_length), status);

    PROCEND set_status_damaged_attributes;
?? OLDTITLE ??
?? EJECT ?? {fsp#expand_file_label

    VAR {!?Kludge to get FMV$SYSTEM_FILE_ATTRIBUTES ?!
      var_addr: pmt$loaded_address,
      v#system_file_attributes: [STATIC] bat$static_label_attributes,
      first_time: [STATIC] boolean := TRUE;

    status.normal := TRUE;

    IF first_time THEN
      pmp$load ('FMV$SYSTEM_FILE_ATTRIBUTES     ', pmc$data_address, var_addr, status);
      fip#move (var_addr.pointer_to_data, ^v#system_file_attributes,
            #SIZE (v#system_file_attributes));
      first_time := FALSE;
    IFEND;
    label_atts := v#system_file_attributes;

    IF file_label_p = NIL THEN
      file_previously_opened := FALSE;
      RETURN; {----->
    IFEND;

    static_label_p := file_label_p;
    RESET static_label_p;
    NEXT header_p IN static_label_p;
    IF header_p = NIL THEN
      set_status_damaged_attributes (fmc$highest_current_attribute + 4, status);
      RETURN; {----->
    IFEND;
    IF header_p^.unique_character <> fmc$unique_label_id THEN
      set_status_damaged_attributes (fmc$highest_current_attribute + 5, status);
      RETURN; {----->
    IFEND;
    file_previously_opened := header_p^.file_previously_opened;
    IF header_p^.file_previously_opened THEN
      label_atts.ring_attributes_source := header_p^.ring_attributes_source;
      label_atts.ring_attributes := header_p^.ring_attributes;
    IFEND;

    IF header_p^.highest_attribute_present = 0 THEN
      RETURN; {----->
    IFEND;
    reassign_file_contents := FALSE;
    set_retrievable_label_atts (requested_label_atts, present_label_atts_n);
    IF present_label_atts_n = 0 THEN
      RETURN; {----->
    IFEND;
    name_p := ^null_string; {!?need better value?!
    path_p := ^null_string;

  /get_attributes/
    FOR attribute_key := LOWERBOUND (header_p^.attribute_present) TO header_p^.
          highest_attribute_present DO

      IF header_p^.attribute_present [attribute_key] THEN
        CASE attribute_key OF

        = fmc$average_record_length =
          NEXT label_item_p: [fmc$average_record_length] IN static_label_p;

        = fmc$block_type =
          NEXT label_item_p: [fmc$block_type] IN static_label_p;

        = fmc$character_conversion =
          NEXT label_item_p: [fmc$character_conversion] IN static_label_p;

        = fmc$clear_space =
          NEXT label_item_p: [fmc$clear_space] IN static_label_p;

        = fmc$collate_table =
          NEXT label_item_p: [fmc$collate_table] IN static_label_p;

        = fmc$collate_table_name =
          NEXT label_item_p: [fmc$collate_table_name] IN static_label_p;
          get_entry_point_reference (name_p, path_p);

        = fmc$compression_procedure_name =
          NEXT label_item_p: [fmc$compression_procedure_name] IN static_label_p;
          get_entry_point_reference (name_p, path_p);

        = fmc$data_padding =
          NEXT label_item_p: [fmc$data_padding] IN static_label_p;

        = fmc$dynamic_home_block_space =
          NEXT label_item_p: [fmc$dynamic_home_block_space] IN static_label_p;

        = fmc$embedded_key =
          NEXT label_item_p: [fmc$embedded_key] IN static_label_p;

        = fmc$estimated_record_count =
          NEXT label_item_p: [fmc$estimated_record_count] IN static_label_p;

        = fmc$file_access_procedure =
          NEXT label_item_p: [fmc$file_access_procedure] IN static_label_p;
          get_entry_point_reference (name_p, path_p);

        = fmc$file_contents =
          NEXT label_item_p: [fmc$file_contents] IN static_label_p;
          get_name (name_p);

        = fmc$file_limit =
          NEXT label_item_p: [fmc$file_limit] IN static_label_p;

        = fmc$file_organization =
          NEXT label_item_p: [fmc$file_organization] IN static_label_p;

        = fmc$file_processor =
          NEXT label_item_p: [fmc$file_processor] IN static_label_p;
          get_name (name_p);

        = fmc$file_structure =
          NEXT label_item_p: [fmc$file_structure] IN static_label_p;
          get_name (name_p);

        = fmc$forced_write =
          NEXT label_item_p: [fmc$forced_write] IN static_label_p;

        = fmc$hashing_procedure_name =
          NEXT label_item_p: [fmc$hashing_procedure_name] IN static_label_p;
          get_entry_point_reference (name_p, path_p);

        = fmc$index_levels =
          NEXT label_item_p: [fmc$index_levels] IN static_label_p;

        = fmc$index_padding =
          NEXT label_item_p: [fmc$index_padding] IN static_label_p;

        = fmc$initial_home_block_count =
          NEXT label_item_p: [fmc$initial_home_block_count] IN static_label_p;

        = fmc$internal_code =
          NEXT label_item_p: [fmc$internal_code] IN static_label_p;

        = fmc$key_length =
          NEXT label_item_p: [fmc$key_length] IN static_label_p;

        = fmc$key_position =
          NEXT label_item_p: [fmc$key_position] IN static_label_p;

        = fmc$key_type =
          NEXT label_item_p: [fmc$key_type] IN static_label_p;

        = fmc$label_type =
          NEXT label_item_p: [fmc$label_type] IN static_label_p;

        = fmc$line_number =
          NEXT label_item_p: [fmc$line_number] IN static_label_p;

        = fmc$loading_factor =
          NEXT label_item_p: [fmc$loading_factor] IN static_label_p;

        = fmc$lock_expiration_time =
          NEXT label_item_p: [fmc$lock_expiration_time] IN static_label_p;

        = fmc$log_residence =
          NEXT label_item_p: [fmc$log_residence] IN static_label_p;
          IF label_item_p <> NIL THEN
            NEXT path_p: [label_item_p^.path_length] IN static_label_p;
          IFEND;

        = fmc$logging_options =
          NEXT label_item_p: [fmc$logging_options] IN static_label_p;

        = fmc$max_block_length =
          NEXT label_item_p: [fmc$max_block_length] IN static_label_p;

        = fmc$max_record_length =
          NEXT label_item_p: [fmc$max_record_length] IN static_label_p;

        = fmc$min_block_length =
          NEXT label_item_p: [fmc$min_block_length] IN static_label_p;

        = fmc$min_record_length =
          NEXT label_item_p: [fmc$min_record_length] IN static_label_p;

        = fmc$padding_character =
          NEXT label_item_p: [fmc$padding_character] IN static_label_p;

        = fmc$page_format =
          NEXT label_item_p: [fmc$page_format] IN static_label_p;

        = fmc$page_length =
          NEXT label_item_p: [fmc$page_length] IN static_label_p;

        = fmc$page_width =
          NEXT label_item_p: [fmc$page_width] IN static_label_p;

        = fmc$preset_value =
          NEXT label_item_p: [fmc$preset_value] IN static_label_p;

        = fmc$record_delimiting_character =
          NEXT label_item_p: [fmc$record_delimiting_character] IN static_label_p;

        = fmc$record_limit =
          NEXT label_item_p: [fmc$record_limit] IN static_label_p;

        = fmc$record_type =
          NEXT label_item_p: [fmc$record_type] IN static_label_p;

        = fmc$records_per_block =
          NEXT label_item_p: [fmc$records_per_block] IN static_label_p;

        = fmc$ring_attributes = {processed above prior to FOR loop
          CYCLE /get_attributes/; {----->

        = fmc$statement_identifier =
          NEXT label_item_p: [fmc$statement_identifier] IN static_label_p;

        = fmc$user_info =
          NEXT label_item_p: [fmc$user_info] IN static_label_p;
          IF (label_item_p <> NIL) AND (label_item_p^.user_info_present) THEN
            NEXT path_p: [32] IN static_label_p;
          IFEND;

        = fmc$vertical_print_density =
          NEXT label_item_p: [fmc$vertical_print_density] IN static_label_p;

        CASEND;

        IF (label_item_p = NIL) OR (name_p = NIL) OR (path_p = NIL) THEN
          set_status_damaged_attributes (attribute_key, status);
          RETURN; {----->
        IFEND;

        IF attribute_key IN requested_label_atts THEN

          CASE attribute_key OF

          = fmc$average_record_length =
            label_atts.average_record_length_source := label_item_p^.source;
            label_atts.average_record_length := label_item_p^.integer_value;

          = fmc$block_type =
            label_atts.block_type_source := label_item_p^.source;
            label_atts.block_type := label_item_p^.block_type;

          = fmc$character_conversion =
            label_atts.character_conversion_source := label_item_p^.source;
            label_atts.character_conversion := label_item_p^.character_conversion;

          = fmc$clear_space =
            label_atts.clear_space_source := label_item_p^.source;
            label_atts.clear_space := label_item_p^.clear_space;

          = fmc$collate_table =
            label_atts.collate_table_source := label_item_p^.source;
            label_atts.collate_table := label_item_p^.collate_table;

          = fmc$collate_table_name =
            label_atts.collate_table_name_source := label_item_p^.source;
            label_atts.collate_table_name := name_p^;

          = fmc$compression_procedure_name =
            label_atts.compression_proc_name_source := label_item_p^.source;
            label_atts.compression_procedure_name.name := name_p^;
            label_atts.compression_procedure_name.object_library := path_p^;

          = fmc$data_padding =
            label_atts.data_padding_source := label_item_p^.source;
            label_atts.data_padding := label_item_p^.data_padding;

          = fmc$dynamic_home_block_space =
            label_atts.dynamic_home_block_space_source := label_item_p^.source;
            label_atts.dynamic_home_block_space := label_item_p^.dynamic_home_block_space;

          = fmc$embedded_key =
            label_atts.embedded_key_source := label_item_p^.source;
            label_atts.embedded_key := label_item_p^.embedded_key;

          = fmc$estimated_record_count =
            label_atts.estimated_record_count_source := label_item_p^.source;
            label_atts.estimated_record_count := label_item_p^.integer_value;

          = fmc$file_access_procedure =
            label_atts.file_access_procedure_source := label_item_p^.source;
            label_atts.file_access_procedure := name_p^;

          = fmc$file_contents =
            label_atts.file_contents_source := label_item_p^.source;
            label_atts.file_contents := name_p^;
            fsp$convert_to_old_contents (label_atts.file_contents, split_file_contents,
                  split_file_structure);
            reassign_file_contents := split_file_structure <> fsc$unknown_contents;

          = fmc$file_limit =
            label_atts.file_limit_source := label_item_p^.source;
            label_atts.file_limit := label_item_p^.integer_value;

          = fmc$file_organization =
            label_atts.file_organization_source := label_item_p^.source;
            label_atts.file_organization := label_item_p^.file_organization;

          = fmc$file_processor =
            label_atts.file_processor_source := label_item_p^.source;
            label_atts.file_processor := name_p^;

          = fmc$file_structure =
            label_atts.file_structure_source := label_item_p^.source;
            label_atts.file_structure := name_p^;

          = fmc$forced_write =
            label_atts.forced_write_source := label_item_p^.source;
            label_atts.forced_write := label_item_p^.forced_write;

          = fmc$hashing_procedure_name =
            label_atts.hashing_procedure_name_source := label_item_p^.source;
            label_atts.hashing_procedure_name.name := name_p^;
            label_atts.hashing_procedure_name.object_library := path_p^;

          = fmc$index_levels =
            label_atts.index_levels_source := label_item_p^.source;
            label_atts.index_levels := label_item_p^.integer_value;

          = fmc$index_padding =
            label_atts.index_padding_source := label_item_p^.source;
            label_atts.index_padding := label_item_p^.index_padding;

          = fmc$initial_home_block_count =
            label_atts.initial_home_block_count_source := label_item_p^.source;
            label_atts.initial_home_block_count := label_item_p^.integer_value;

          = fmc$internal_code =
            label_atts.internal_code_source := label_item_p^.source;
            label_atts.internal_code := label_item_p^.internal_code;

          = fmc$key_length =
            label_atts.key_length_source := label_item_p^.source;
            label_atts.key_length := label_item_p^.integer_value;

          = fmc$key_position =
            label_atts.key_position_source := label_item_p^.source;
            label_atts.key_position := label_item_p^.integer_value;

          = fmc$key_type =
            label_atts.key_type_source := label_item_p^.source;
            label_atts.key_type := label_item_p^.key_type;

          = fmc$label_type =
            label_atts.label_type_source := label_item_p^.source;
            label_atts.label_type := label_item_p^.label_type;

          = fmc$line_number =
            IF (label_item_p^.line_number.length >=
                  LOWERVALUE (amt$line_number_length)) AND
                  (label_item_p^.line_number.length <=
                  UPPERVALUE (amt$line_number_length)) AND
                  (label_item_p^.line_number.location >=
                  LOWERVALUE (amt$line_number_location)) AND
                  (label_item_p^.line_number.location <=
                  UPPERVALUE (amt$line_number_location)) THEN
              label_atts.line_number_source := label_item_p^.source;
              label_atts.line_number := label_item_p^.line_number;
            IFEND;

          = fmc$loading_factor =
            label_atts.loading_factor_source := label_item_p^.source;
            label_atts.loading_factor := label_item_p^.loading_factor;

          = fmc$lock_expiration_time =
            label_atts.lock_expiration_time_source := label_item_p^.source;
            label_atts.lock_expiration_time := label_item_p^.integer_value;

          = fmc$log_residence =
            label_atts.log_residence_source := label_item_p^.source;
            label_atts.log_residence := path_p^;

          = fmc$logging_options =
            label_atts.logging_options_source := label_item_p^.source;
            label_atts.logging_options := label_item_p^.logging_options;

          = fmc$max_block_length =
            label_atts.max_block_length_source := label_item_p^.source;
            label_atts.max_block_length := label_item_p^.integer_value;

          = fmc$max_record_length =
            label_atts.max_record_length_source := label_item_p^.source;
            label_atts.max_record_length := label_item_p^.integer_value;

          = fmc$min_block_length =
            label_atts.min_block_length_source := label_item_p^.source;
            label_atts.min_block_length := label_item_p^.integer_value;

          = fmc$min_record_length =
            label_atts.min_record_length_source := label_item_p^.source;
            label_atts.min_record_length := label_item_p^.integer_value;

          = fmc$padding_character =
            label_atts.padding_character_source := label_item_p^.source;
            label_atts.padding_character := label_item_p^.padding_character;

          = fmc$page_format =
            label_atts.page_format_source := label_item_p^.source;
            label_atts.page_format := label_item_p^.page_format;

          = fmc$page_length =
            label_atts.page_length_source := label_item_p^.source;
            label_atts.page_length := label_item_p^.integer_value;

          = fmc$page_width =
            label_atts.page_width_source := label_item_p^.source;
            label_atts.page_width := label_item_p^.integer_value;

          = fmc$preset_value =
            label_atts.preset_value_source := label_item_p^.source;
            label_atts.preset_value := label_item_p^.integer_value;

          = fmc$record_delimiting_character =
            label_atts.record_delimiting_char_source := label_item_p^.source;
            label_atts.record_delimiting_character :=
                  label_item_p^.record_delimiting_character;

          = fmc$record_limit =
            label_atts.record_limit_source := label_item_p^.source;
            label_atts.record_limit := label_item_p^.integer_value;

          = fmc$record_type =
            label_atts.record_type_source := label_item_p^.source;
            label_atts.record_type := label_item_p^.record_type;

          = fmc$records_per_block =
            label_atts.records_per_block_source := label_item_p^.source;
            label_atts.records_per_block := label_item_p^.integer_value;

          = fmc$ring_attributes = {processed above prior to this loop

          = fmc$statement_identifier =
            IF (label_item_p^.statement_identifier.length >=
                  LOWERVALUE (amt$statement_id_length)) AND
                  (label_item_p^.statement_identifier.length <=
                  UPPERVALUE (amt$statement_id_length)) AND
                  (label_item_p^.statement_identifier.location >=
                  LOWERVALUE (amt$statement_id_location)) AND
                  (label_item_p^.statement_identifier.location <=
                  UPPERVALUE (amt$statement_id_location)) THEN
              label_atts.statement_identifier_source := label_item_p^.source;
              label_atts.statement_identifier := label_item_p^.statement_identifier;
            IFEND;

          = fmc$user_info =
            label_atts.user_info_source := label_item_p^.source;
            IF label_item_p^.user_info_present THEN
              label_atts.user_info := path_p^;
            IFEND;

          = fmc$vertical_print_density =
            label_atts.vertical_print_density_source := label_item_p^.source;
            label_atts.vertical_print_density := label_item_p^.integer_value;

          CASEND;

          present_label_atts_n := present_label_atts_n - 1;
          IF present_label_atts_n = 0 THEN {Need anymore?
            EXIT /get_attributes/; {----->
          IFEND;

        IFEND; {attribute_key in requested_label_atts
      IFEND; {attribute_present in header
    FOREND /get_attributes/;

    IF reassign_file_contents AND NOT ((split_file_contents = fsc$list) AND
          (split_file_structure = fsc$data) AND (label_atts.file_structure =
          fsc$unknown_contents)) THEN
      label_atts.file_contents := split_file_contents;
      label_atts.file_structure := split_file_structure;
      label_atts.file_structure_source := label_atts.file_contents_source;
    IFEND;

  PROCEND fsp#expand_file_label;
?? OLDTITLE ??
MODEND fsm#expand_file_label;
