?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE CM : Access Device Files' ??
MODULE cmm$access_device_files;

{ PURPOSE:

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cme$logical_configuration_mgr
*copyc cme$access_device_files
*copyc cmc$default_vsn
*copyc cmt$device_file_header
*copyc cmk$keypoints
*copyc gft$system_file_identifier
*copyc osd$integer_limits
?? POP ??
*copyc amp$get_next
*copyc amp$put_next
*copyc cmp$change_new_df_entry
*copyc cmp$manage_device_file_lock
*copyc dmp$attach_device_file
*copyc dmp$close_file
*copyc dmp$detach_device_file
*copyc dmp$open_file
*copyc i#move
*copyc mmp$write_modified_pages
*copyc osp$append_status_parameter
*copyc osp$set_status_abnormal
?? EJECT ??
*copyc cmv$new_device_file
*copyc cmv$physical_configuration
  VAR
    cmv$use_installed_configuration : [XREF] boolean;
*copyc dmv$system_device_information
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??
  CONST
    c$current_version_number = 'SECOND VERSION NUMBER 2        ';
?? OLDTITLE ??
?? NEWTITLE := 'attach_device_file', EJECT ??

  PROCEDURE attach_device_file
    (    device_file_name: ost$name;
         recorded_vsn: rmt$recorded_vsn;
     VAR segment_pointer: mmt$segment_pointer;
     VAR system_file_id: gft$system_file_identifier;
     VAR status: ost$status);

    status.normal := TRUE;

    dmp$attach_device_file (recorded_vsn, device_file_name, system_file_id, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    segment_pointer.kind := mmc$sequence_pointer;
    dmp$open_file (system_file_id, osc$tsrv_ring, osc$tsrv_ring, mmc$sar_write_extend, mmc$as_random,
          segment_pointer, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

  PROCEND attach_device_file;
?? OLDTITLE ??
?? NEWTITLE := 'close_device_file', EJECT ??

  PROCEDURE close_device_file
    (    segment_p: mmt$segment_pointer;
         system_file_id: gft$system_file_identifier;
     VAR status: ost$status);

    VAR
      file_modified: boolean,
      fmd_modified: boolean;

    status.normal := TRUE;
    dmp$close_file (#LOC (segment_p.seq_pointer^), status);
    IF status.normal THEN
      dmp$detach_device_file (system_file_id, file_modified, fmd_modified, status);
    IFEND;

  PROCEND close_device_file;
?? OLDTITLE ??
?? NEWTITLE := 'copy_bam_file_to_df', EJECT ??

  PROCEDURE copy_bam_file_to_df
    (    bam_fid: amt$file_identifier;
         file_status: cmt$device_file_status;
         file_version: ost$name;
     VAR seq_p: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      bam_el: string (osc$max_string_size),
      byte_address: amt$file_byte_address,
      cell_p: ^cell,
      df_header_p: ^cmt$device_file_header_v2,
      file_position: amt$file_position,
      ignore_status: ost$status,
      line_count: integer,
      size_line_p: ^ost$non_negative_integers,
      text_el_p: ^string ( * ),
      transfer_count: amt$transfer_count;

    status.normal := TRUE;

   /main_program/
    BEGIN
      RESET seq_p;
      NEXT df_header_p IN seq_p;
      df_header_p^.being_updated := cmc$being_updated;
      mmp$write_modified_pages (df_header_p, #SIZE (cmt$device_file_header_v2), osc$wait, status);
      IF NOT status.normal THEN
        EXIT /main_program/;
      IFEND;

      df_header_p^.version := file_version;
      df_header_p^.status := file_status;

      { Move the information to the device file.

      line_count := 0;

     /read_loop/
      WHILE TRUE DO
        amp$get_next (bam_fid, ^bam_el, #SIZE (bam_el), transfer_count, byte_address, file_position, status);
        IF NOT status.normal THEN
          EXIT /main_program/;
        IFEND;
        IF file_position = amc$eoi THEN
          EXIT /read_loop/;
        IFEND;
        NEXT size_line_p IN seq_p;
        size_line_p^ := transfer_count;
        NEXT text_el_p: [transfer_count] IN seq_p;
        cell_p := ^bam_el;
        i#move (cell_p, text_el_p, transfer_count);
        line_count := line_count + 1;
      WHILEND /read_loop/;

      df_header_p^.length := line_count;
      df_header_p^.changed := TRUE;
      mmp$write_modified_pages (df_header_p, line_count + #SIZE (cmt$device_file_header_v2), osc$wait,
            status);
      IF NOT status.normal THEN
        EXIT /main_program/;
      IFEND;
    END /main_program/;

    { Set the being_updated flag to false and write pages to disk.

    df_header_p^.being_updated := cmc$valid_data_in_file;
    mmp$write_modified_pages (df_header_p, #SIZE (cmt$device_file_header_v2), osc$wait, ignore_status);

  PROCEND copy_bam_file_to_df;
?? OLDTITLE ??
?? NEWTITLE := 'copy_df_to_bam_file', EJECT ??

  PROCEDURE copy_df_to_bam_file
    (    bam_fid: amt$file_identifier;
     VAR seq_p: ^SEQ ( * );
     VAR status: ost$status);

    VAR
      df_header_p: ^cmt$device_file_header_v2,
      ignore_file_byte_address : amt$file_byte_address,
      loop_index: integer,
      size_line_p: ^ost$non_negative_integers,
      text_el_p: ^string ( * );

    status.normal := TRUE;
    RESET seq_p;
    NEXT df_header_p IN seq_p;
    IF df_header_p^.being_updated <> cmc$valid_data_in_file THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$adf_incomplete_device_file,
            cmv$new_device_file.name, status);
      RETURN;
    IFEND;

    IF df_header_p^.version <> c$current_version_number THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$adf_illegal_version,
            df_header_p^.version, status);
      RETURN;
    IFEND;

    { Move the information from the device file.

    FOR loop_index := 1 TO df_header_p^.length DO
      NEXT size_line_p IN seq_p;
      NEXT text_el_p: [size_line_p^] IN seq_p;
      IF text_el_p <> NIL THEN
        amp$put_next (bam_fid, text_el_p, size_line_p^, ignore_file_byte_address, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
      IFEND;
    FOREND;

  PROCEND copy_df_to_bam_file;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$copy_active_configuration', EJECT ??

  PROCEDURE [XDCL, #GATE] cmp$copy_active_configuration
    (VAR configuration_p: ^ARRAY [1 .. *] OF cmt$element_definition;
     VAR status: ost$status);

    VAR
      index: integer;

    status.normal := TRUE;
    FOR index := 1 TO UPPERBOUND (cmv$physical_configuration^) DO
      configuration_p^ [index] := cmv$physical_configuration^ [index];
    FOREND;

  PROCEND cmp$copy_active_configuration;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$get_conf_file', EJECT ??

{ PURPOSE:
{   This procedure retrieves either the logical or physical configuration stored on a device file.  The data
{   is stored on a BAM file with segment access in the form of a sequence.  The device file is either active
{   or installed.

  PROCEDURE [XDCL, #GATE] cmp$get_conf_file
    (    bam_fid: amt$file_identifier;
     VAR status: ost$status);

    VAR
      df_header_p: ^cmt$device_file_header_v2,
      close_status: ost$status,
      segment_pointer: mmt$segment_pointer,
      sfid: gft$system_file_identifier;

    status.normal := TRUE;
    #KEYPOINT (osk$entry, 0, cmk$get_conf_file);

    attach_device_file (cmv$new_device_file.name, cmv$new_device_file.recorded_vsn, segment_pointer, sfid,
          status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

   /file_open/
    BEGIN
      RESET segment_pointer.seq_pointer;
      NEXT df_header_p IN segment_pointer.seq_pointer;
      IF df_header_p = NIL THEN
        osp$set_status_abnormal (cmc$configuration_management_id, cme$adf_nil_element_pointer, 'DEVICE FILE',
              status);
        osp$append_status_parameter (osc$status_parameter_delimiter, 'CMP$GET_CONF_FILE', status);
        EXIT /file_open/;
      IFEND;

      IF df_header_p^.being_updated <> cmc$valid_data_in_file THEN
        osp$set_status_abnormal (cmc$configuration_management_id, cme$adf_incomplete_device_file,
              cmv$new_device_file.name, status);
        EXIT /file_open/;
      IFEND;
      copy_df_to_bam_file (bam_fid, segment_pointer.seq_pointer, status);
    END /file_open/;

    close_device_file (segment_pointer, sfid, close_status);
    IF status.normal THEN
      status := close_status;
    IFEND;
    IF NOT status.normal AND NOT cmv$use_installed_configuration THEN
      status.normal := TRUE;
    IFEND;
    #KEYPOINT (osk$exit, 0, cmk$get_conf_file);

  PROCEND cmp$get_conf_file;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$get_number_of_element', EJECT ??

  PROCEDURE [XDCL, #GATE] cmp$get_number_of_element
    (VAR element_count: integer;
     VAR status: ost$status);

    status.normal := TRUE;
    IF cmv$physical_configuration = NIL THEN
      osp$set_status_abnormal (cmc$configuration_management_id, cme$lcm_empty_lc, ' ', status);
      RETURN;
    IFEND;

    element_count := UPPERBOUND (cmv$physical_configuration^);

  PROCEND cmp$get_number_of_element;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$initialize_dft', EJECT ??

{ PURPOSE:
{   This procedure initializes the device file table.  This procedure will attach each device file, validate
{   the status of the file, and set the corresponding entry in the device file table.

  PROCEDURE [XDCL] cmp$initialize_dft
    (VAR status: ost$status);

    VAR
      device_file_record: cmt$device_file_record,
      df_header_p: ^cmt$device_file_header_v2,
      ignore_status: ost$status,
      recorded_vsn: rmt$recorded_vsn,
      segment_pointer: mmt$segment_pointer,
      system_file_id: gft$system_file_identifier;

    status.normal := TRUE;
    #KEYPOINT (osk$entry, 0, cmk$initialize_dft);

   /main_program/
    BEGIN
      device_file_record := cmv$new_device_file;
      recorded_vsn := cmv$new_device_file.recorded_vsn;
      IF recorded_vsn = cmc$default_vsn THEN
        recorded_vsn := dmv$system_device_recorded_vsn;
        device_file_record.recorded_vsn := recorded_vsn;
      IFEND;
      attach_device_file (device_file_record.name, recorded_vsn, segment_pointer, system_file_id, status);
      IF NOT status.normal THEN
        EXIT /main_program/;
      IFEND;

      RESET segment_pointer.seq_pointer;
      NEXT df_header_p IN segment_pointer.seq_pointer;
      IF df_header_p = NIL THEN
        osp$set_status_abnormal (cmc$configuration_management_id, cme$adf_nil_element_pointer, 'DEVICE FILE',
              status);
        osp$append_status_parameter (osc$status_parameter_delimiter, 'CMP$INITIALIZE_DFT', status);
        close_device_file (segment_pointer, system_file_id, ignore_status);
        EXIT /main_program/;
      IFEND;

      device_file_record.version := df_header_p^.version;
      device_file_record.status := df_header_p^.status;
      device_file_record.relative_time := df_header_p^.relative_time;
      close_device_file (segment_pointer, system_file_id, status);
      cmp$change_new_df_entry (device_file_record);
    END /main_program/;

    #KEYPOINT (osk$exit, 0, cmk$initialize_dft);

  PROCEND cmp$initialize_dft;
?? OLDTITLE ??
?? NEWTITLE := 'cmp$install_conf_file', EJECT ??

{ PURPOSE:
{   This procedure installs the bam file provided as a device file and marks the device file as installed,
{   both on the device file and in the device file table.

  PROCEDURE [XDCL, #GATE] cmp$install_conf_file
    (    bam_fid: amt$file_identifier;
     VAR status: ost$status);

    VAR
      close_status: ost$status,
      device_file_record: cmt$device_file_record,
      df_header_p: ^cmt$device_file_header_v2,
      segment_pointer: mmt$segment_pointer,
      system_file_id: gft$system_file_identifier;

    status.normal := TRUE;

    { Set global lock to prevent concurrent update of the device file.

    cmp$manage_device_file_lock ({set_lock = }TRUE, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

   /lock_set/
    BEGIN
      attach_device_file (cmv$new_device_file.name, cmv$new_device_file.recorded_vsn, segment_pointer,
            system_file_id, status);
      IF NOT status.normal THEN
        EXIT /lock_set/;
      IFEND;

     /file_open/
      BEGIN

        { Update headers.

        RESET segment_pointer.seq_pointer;
        NEXT df_header_p IN segment_pointer.seq_pointer;
        IF df_header_p = NIL THEN
          osp$set_status_abnormal (cmc$configuration_management_id, cme$adf_nil_element_pointer,
                'DEVICE FILE', status);
          osp$append_status_parameter (osc$status_parameter_delimiter, 'CMP$INSTALL_CONF_FILE', status);
          EXIT /file_open/;
        IFEND;

        copy_bam_file_to_df (bam_fid, cmc$dfs_active, c$current_version_number, segment_pointer.seq_pointer,
              status);
        IF NOT status.normal THEN
          EXIT /file_open/;
        IFEND;

        device_file_record := cmv$new_device_file;
        device_file_record.status := cmc$dfs_active;
        device_file_record.version := c$current_version_number;
        cmp$change_new_df_entry (device_file_record);
      END /file_open/;

      close_device_file (segment_pointer, system_file_id, close_status);
      IF status.normal THEN
        status := close_status;
      IFEND;
    END /lock_set/;
    cmp$manage_device_file_lock ({set_lock = }FALSE, close_status);
    IF status.normal THEN
      status := close_status;
    IFEND;

    #KEYPOINT (osk$entry, 0, cmk$install_conf_file);

  PROCEND cmp$install_conf_file;
?? OLDTITLE ??
MODEND cmm$access_device_files;
