?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Device Management : VED MS Display' ??

MODULE dmm$display_mass_storage;
{
{  This module is placed on the following library
{   OSF$JOB_TEMPLATE_223

{
{ PURPOSE:
{  This module contains the ring 3 procedure that executes the
{  DISPLAY_MASS_STORAGE Operator Facility Command.
{

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc oss$job_paged_literal
*copyc oss$task_private
*copyc clt$value
*copyc osd$virtual_address
*copyc dmt$active_volume_table_index
*copyc dmt$error_condition_codes
*copyc dmt$out_of_space_sets
*copyc ost$status
*copyc ost$string
?? POP ??
*copyc amp$put_next
*copyc clp$close_display
*copyc clp$new_display_line
*copyc clp$open_display_file
*copyc clp$put_display
*copyc cmp$get_element_entry_via_lun
*copyc dmp$calculate_device_capacity
*copyc dmp$get_allocation_info
*copyc dpp$clear_window
*copyc dpp$put_next_line
*copyc ofp$open_display
*copyc ofp$get_next_avt_index
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc osp$set_status_abnormal
*copyc dmv$active_volume_table
*copyc ofv$mass_storage_display_infos

  VAR
    dmv$q_devices_added: [XREF] integer;

?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] dmp$display_mass_storage', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$display_mass_storage
    (    wid: dpt$window_id;
         display_name: ost$name;
         file_name: amt$local_file_name;
         initial_call: boolean;
     VAR status: ost$status);

    CONST
      c$mega_bytes = 1024 * 1024;

    VAR
      v$title: [READ, oss$job_paged_literal] array [boolean] of array [boolean] of string (80) := [
{ DAUS           } [
{   MAT&DAT        } ' Index  VSN    MAT Space    Status     Alloc  DAT Space    Transfer Count       ',
{   CAPACITY&AVAIL } ' Index  VSN    Avail Space  Status     Alloc  Capacity     Transfer Count       '],
{ MBYTES         } [
{   MAT&DAT        } ' Index  VSN    MAT MBytes   Status     Alloc  DAT MBytes   Transfer Count       ',
{   CAPACITY&AVAIL } ' Index  VSN    Avail MB     Status     Alloc  Capacity MB  Transfer Count       ']];

    VAR
      allocation_info: dmt$allocation_info,
      avt_index: dmt$active_volume_table_index,
      class: dmt$class_member,
      class_index: integer,
      classes: dmt$class,
      control: oft$msdi_volume_access_control,
      display_control: clt$display_control,
      display_line: string (80),
      entry_p: ^cmt$peripheral_element_entry,
      eot: boolean,
      ignore_status: ost$status,
      index: integer,
      integer_string: string (16),
      line: string (132),
      line_length: integer,
      lun: iot$logical_unit,
      name_length: integer,
      p_out_of_space_sets: ^dmt$out_of_space_sets,
      set_count: integer,
      set_name: stt$set_name,
      string_length: integer,
      title_p: ^string (80),
      vsn: rmt$recorded_vsn;

?? NEWTITLE := 'abort_handler', EJECT ??

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

      IF wid = 0 THEN
        clp$close_display (display_control, ignore_status);
      IFEND;

    PROCEND abort_handler;
?? OLDTITLE, EJECT ??

    status.normal := TRUE;

    IF wid = 0 THEN
      osp$establish_block_exit_hndlr (^abort_handler);
    IFEND;

    IF initial_call OR (wid = 0) THEN
      title_p := ^v$title [ofv$mass_storage_display_infos [ofc$ved_ms].space_quantity =
            ofc$msdi_mbytes] [ofv$mass_storage_display_infos [ofc$ved_ms].space_selection =
            ofc$msdi_capacity_available];
      ofp$open_display (file_name, wid, dpc$wc_sharing, dpc$wk_table, title_p^, display_control, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;
    IFEND;

    line_length := 80;
    IF (wid = 0) THEN
      IF (display_control.page_width > line_length) THEN
        IF (display_control.page_width > STRLENGTH (line)) THEN
          line_length := STRLENGTH (line);
        ELSE
          line_length := display_control.page_width;
        IFEND;
      IFEND;
    IFEND;

    IF wid = 0 THEN
      display_line := '  ';
      clp$put_display (display_control, display_line, clc$trim, status);
    ELSE
      dpp$clear_window (wid, status);
    IFEND;
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF ofc$msdi_classes_out_of_space IN ofv$mass_storage_display_infos [ofc$ved_ms].display_options.
          values THEN
      PUSH p_out_of_space_sets: [1 .. UPPERBOUND (dmv$active_volume_table.table_p^) + 1];
      dmp$get_out_of_space_sets (p_out_of_space_sets^, set_count);

      FOR index := 1 TO set_count DO
        set_name := p_out_of_space_sets^ [index].set_name;
        classes := p_out_of_space_sets^ [index].classes;
        IF (classes <> $dmt$class []) THEN
          IF (set_name = osc$null_name) THEN
            STRINGREP (line, string_length, ' Classes out of space:');
          ELSE
            name_length := STRLENGTH (set_name);
            WHILE (name_length > 0) AND (set_name (name_length) = ' ') DO
              name_length := name_length - 1;
            WHILEND;
            STRINGREP (line, string_length, ' ', set_name (1, name_length), ' classes out of space:');
          IFEND;
          class_index := string_length + 1;

          FOR class := LOWERVALUE (dmt$class_member) TO UPPERVALUE (dmt$class_member) DO
            IF class IN classes THEN
              IF (class_index >= line_length) THEN
                IF wid = 0 THEN
                  clp$put_display (display_control, line (1, class_index - 1), clc$trim, status);
                ELSE
                  dpp$put_next_line (wid, line (1, class_index - 1), status);
                IFEND;
                IF NOT status.normal THEN
                  RETURN; {----->
                IFEND;
                line (1, string_length) := ' ';
                class_index := string_length + 1;
              IFEND;
              line (class_index, 1) := ' ';
              line (class_index + 1, 1) := $CHAR ($INTEGER (class));
              class_index := class_index + 2;
            IFEND;
          FOREND;

          IF wid = 0 THEN
            clp$put_display (display_control, line (1, class_index - 1), clc$trim, status);
          ELSE
            dpp$put_next_line (wid, line (1, class_index - 1), status);
          IFEND;
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;
        IFEND;
      FOREND;
    IFEND;

    IF ofc$msdi_crit_class_added_count IN ofv$mass_storage_display_infos [ofc$ved_ms].display_options.
          values THEN
      IF dmv$q_devices_added <> 0 THEN
        display_line := '  ';
        STRINGREP (display_line, string_length, ' Class Q devices automatically added: ',
              dmv$q_devices_added);
        IF wid = 0 THEN
          clp$put_display (display_control, display_line, clc$trim, status);
        ELSE
          dpp$put_next_line (wid, display_line, status);
        IFEND;
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
      IFEND;
    IFEND;

    control.last_used_index := 0;
    control.sort_option_p := ^ofv$mass_storage_display_infos [ofc$ved_ms].sort_option;
    IF (control.sort_option_p^.key = ofc$msdi_user_defined)
{ } AND (control.sort_option_p^.display_omitted_units) THEN
      PUSH control.avt_entries_displayed_p: [LOWERBOUND (dmv$active_volume_table.table_p^
            ) .. UPPERBOUND (dmv$active_volume_table.table_p^)];
      FOR avt_index := LOWERBOUND (control.avt_entries_displayed_p^)
            TO UPPERBOUND (control.avt_entries_displayed_p^) DO
        control.avt_entries_displayed_p^ [avt_index] := FALSE;
      FOREND;
    ELSE
      control.avt_entries_displayed_p := NIL;
    IFEND;

    REPEAT
      ofp$get_next_avt_index (control, avt_index, eot);
      IF NOT eot THEN
        vsn := dmv$active_volume_table.table_p^ [avt_index].mass_storage.recorded_vsn;

        display_line (1, * ) := ' ';
        STRINGREP (integer_string, string_length, avt_index);
        display_line (2, string_length) := integer_string;
        display_line (2 + string_length, 1) := '.';
        display_line (8, 6) := vsn;

        IF NOT dmv$active_volume_table.table_p^ [avt_index].mass_storage.volume_unavailable THEN

          dmp$get_allocation_info (vsn, avt_index, allocation_info, status);
          IF status.normal THEN
            IF ofv$mass_storage_display_infos [ofc$ved_ms].space_selection = ofc$msdi_capacity_available THEN
{ We misuse available_mat_space for available=MAT+DAT and available_dat_space as capacity

              allocation_info.available_mat_space := allocation_info.available_mat_space +
                    allocation_info.available_dat_space;
              lun := dmv$active_volume_table.table_p^ [avt_index].logical_unit_number;
              allocation_info.available_dat_space := 0;
              cmp$get_element_entry_via_lun (lun, entry_p);
              IF entry_p <> NIL THEN
                dmp$calculate_device_capacity (entry_p^.product_id, allocation_info.available_dat_space,
                      status);
                allocation_info.available_dat_space := allocation_info.available_dat_space DIV
                      allocation_info.bytes_per_dau;
              IFEND;
            IFEND;

            IF ofv$mass_storage_display_infos [ofc$ved_ms].space_quantity = ofc$msdi_mbytes THEN
              allocation_info.available_mat_space := allocation_info.available_mat_space *
                    allocation_info.bytes_per_dau DIV c$mega_bytes;
              allocation_info.available_dat_space := allocation_info.available_dat_space *
                    allocation_info.bytes_per_dau DIV c$mega_bytes;
            IFEND;

            STRINGREP (integer_string, string_length, allocation_info.available_mat_space);
            display_line (16, string_length) := integer_string;

            IF allocation_info.no_space THEN
              display_line (28, 8) := 'no space';
            ELSEIF allocation_info.no_file_entries THEN
              display_line (28, 8) := 'no files';
            ELSEIF allocation_info.space_low THEN
              display_line (28, 9) := 'space low';
            ELSE
              display_line (28, 6) := 'normal';
            IFEND;

            IF allocation_info.allocation_allowed THEN
              display_line (40, 4) := 'true';
            ELSE
              display_line (40, 5) := 'false';
            IFEND;

            STRINGREP (integer_string, string_length, allocation_info.available_dat_space);
            display_line (47, string_length) := integer_string;

            STRINGREP (integer_string, string_length, allocation_info.device_log_count);
            display_line (62, string_length) := integer_string;

          ELSE {probably an io error reading the DAT}
            display_line (16, * ) := 'No available information';
          IFEND;
        ELSE
          IF NOT dmv$active_volume_table.table_p^ [avt_index].mass_storage.logging_process_damaged THEN
            display_line (16, * ) := 'Volume is not available';
          ELSE
            display_line (16, * ) := 'Volume is not available - logging process damaged';
          IFEND;
        IFEND;

        IF wid = 0 THEN
          clp$put_display (display_control, display_line, clc$trim, status);
        ELSE
          dpp$put_next_line (wid, display_line, status);
        IFEND;
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
      IFEND;
    UNTIL eot;

    IF wid = 0 THEN
      clp$close_display (display_control, status);
      osp$disestablish_cond_handler;
    IFEND;


  PROCEND dmp$display_mass_storage;
?? TITLE := '[XDCL, #GATE] dmp$get_out_of_space_sets', EJECT ??
*copy dmh$get_out_of_space_sets

  PROCEDURE [XDCL, #GATE] dmp$get_out_of_space_sets
    (VAR out_of_space_sets: dmt$out_of_space_sets;
     VAR set_count: integer);

    VAR
      avt_index: dmt$active_volume_table_index,
      classes: dmt$class,
      defined_system_classes: dmt$class,
      maximum_set_count: integer,
      non_system_classes: dmt$class,
      not_out: boolean,
      not_out_system_classes: dmt$class,
      p_defined_classes: ^array [1 .. * ] of dmt$class,
      p_not_out_classes: ^array [1 .. * ] of dmt$class,
      set_index: integer,
      set_name: stt$set_name,
      system_classes: dmt$class;

    maximum_set_count := UPPERBOUND (dmv$active_volume_table.table_p^) + 1;
    IF (maximum_set_count > UPPERBOUND (out_of_space_sets)) THEN
      maximum_set_count := UPPERBOUND (out_of_space_sets);
    IFEND;
    PUSH p_defined_classes: [1 .. maximum_set_count];
    PUSH p_not_out_classes: [1 .. maximum_set_count];
    set_count := 1;
    defined_system_classes := $dmt$class [];
    not_out_system_classes := $dmt$class [];

    FOR avt_index := LOWERBOUND (dmv$active_volume_table.table_p^) TO
          UPPERBOUND (dmv$active_volume_table.table_p^) DO
      IF NOT dmv$active_volume_table.table_p^ [avt_index].entry_available THEN
        classes := dmv$active_volume_table.table_p^ [avt_index].mass_storage.class;
        set_name := dmv$active_volume_table.table_p^ [avt_index].mass_storage.set_name;
        out_of_space_sets [1].set_name := set_name;
        set_index := set_count;
        WHILE (out_of_space_sets [set_index].set_name <> set_name) DO
          set_index := set_index - 1;
        WHILEND;

        IF (set_index = 1) THEN {set not in table}
          IF (set_count < maximum_set_count) AND (set_name <> osc$null_name) THEN
            set_count := set_count + 1;
            set_index := set_count;
            out_of_space_sets [set_index].set_name := set_name;
          IFEND;
          p_defined_classes^ [set_index] := $dmt$class [];
          p_not_out_classes^ [set_index] := $dmt$class [];
        IFEND;

        defined_system_classes := defined_system_classes + classes;
        p_defined_classes^ [set_index] := p_defined_classes^ [set_index] + classes;

        not_out := NOT dmv$active_volume_table.table_p^ [avt_index].mass_storage.space_gone AND
              dmv$active_volume_table.table_p^ [avt_index].mass_storage.allocation_allowed AND
              NOT dmv$active_volume_table.table_p^ [avt_index].mass_storage.volume_unavailable;
        IF not_out THEN
          not_out_system_classes := not_out_system_classes + classes;
          p_not_out_classes^ [set_index] := p_not_out_classes^ [set_index] + classes;
        IFEND;
      IFEND;
    FOREND;

    system_classes := $dmt$class ['N', 'Q'];
    non_system_classes := -system_classes;

    out_of_space_sets [1].set_name := osc$null_name;
    out_of_space_sets [1].classes := (defined_system_classes - not_out_system_classes) * system_classes;

    FOR set_index := 2 TO set_count DO
      out_of_space_sets [set_index].classes := (p_defined_classes^ [set_index] -
            p_not_out_classes^ [set_index]) * non_system_classes;
    FOREND;
  PROCEND dmp$get_out_of_space_sets;
?? OLDTITLE ??
MODEND dmm$display_mass_storage;
