?? RIGHT := 110 ??
?? NEWTITLE := ' NOS/VE Backup/Restore Utilities:  restore_object ' ??
MODULE pum$restore_object;

?? PUSH (LISTEXT := ON) ??
*copyc osc$nosve_system_set
*copyc pue$error_condition_codes
*copyc put$selected_object
?? POP ??
*copyc clf$field_value
*copyc avp$family_administrator
*copyc avp$system_administrator
*copyc clp$convert_file_ref_to_string
*copyc clp$evaluate_file_reference
*copyc clp$evaluate_parameters
*copyc osp$append_status_parameter
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc pfp$convert_pft$path_to_string
*copyc pup$build_catalog_header
*copyc pup$build_entry
*copyc pup$close_backup_file
*copyc pup$compare_item_descriptor
*copyc pup$crack_backup_file
*copyc pup$crack_pf_file_reference
*copyc pup$display_restore_totals
*copyc pup$get_summary_status
*copyc pup$initialize_restore_listing
*copyc pup$open_backup_file
*copyc pup$restore_selected_objects
*copyc pup$set_restore_subcmd_defaults
?? TITLE := '    [XDCL] pup$restore_object_command ', EJECT ??

  PROCEDURE [XDCL] pup$restore_object_command
    (    parameter_list: clt$parameter_list;
     VAR status: ost$status);

{ PROCEDURE (osm$reso) restore_objects, restore_object, reso(
{   files, file, f: list of record
{       file: file
{       new_file_name: file = $optional
{     recend = $optional
{   catalogs, catalog, c: list of record
{       catalog: file
{       new_catalog_name: file = $optional
{     recend = $optional
{   backup_file, bf: file = $required
{   status)

?? PUSH (LISTEXT := ON) ??
?? FMT (FORMAT := OFF) ??

  VAR
    pdt: [STATIC, READ, cls$declaration_section] record
      header: clt$pdt_header,
      names: array [1 .. 9] of clt$pdt_parameter_name,
      parameters: array [1 .. 4] of clt$pdt_parameter,
      type1: record
        header: clt$type_specification_header,
        qualifier: clt$list_type_qualifier_v2,
        element_type_spec: record
          header: clt$type_specification_header,
          qualifier: clt$record_type_qualifier,
          field_spec_1: clt$field_specification,
          element_type_spec_1: record
            header: clt$type_specification_header,
          recend,
          field_spec_2: clt$field_specification,
          element_type_spec_2: record
            header: clt$type_specification_header,
          recend,
        recend,
      recend,
      type2: record
        header: clt$type_specification_header,
        qualifier: clt$list_type_qualifier_v2,
        element_type_spec: record
          header: clt$type_specification_header,
          qualifier: clt$record_type_qualifier,
          field_spec_1: clt$field_specification,
          element_type_spec_1: record
            header: clt$type_specification_header,
          recend,
          field_spec_2: clt$field_specification,
          element_type_spec_2: record
            header: clt$type_specification_header,
          recend,
        recend,
      recend,
      type3: record
        header: clt$type_specification_header,
      recend,
      type4: record
        header: clt$type_specification_header,
      recend,
    recend := [
    [1,
    [90, 8, 20, 10, 30, 20, 249],
    clc$command, 9, 4, 1, 0, 0, 0, 4, 'OSM$RESO'], [
    ['BACKUP_FILE                    ',clc$nominal_entry, 3],
    ['BF                             ',clc$abbreviation_entry, 3],
    ['C                              ',clc$abbreviation_entry, 2],
    ['CATALOG                        ',clc$alias_entry, 2],
    ['CATALOGS                       ',clc$nominal_entry, 2],
    ['F                              ',clc$abbreviation_entry, 1],
    ['FILE                           ',clc$alias_entry, 1],
    ['FILES                          ',clc$nominal_entry, 1],
    ['STATUS                         ',clc$nominal_entry, 4]],
    [
{ PARAMETER 1
    [8, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation,
  clc$standard_parameter_checking, 101, clc$optional_parameter, 0, 0],
{ PARAMETER 2
    [5, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation,
  clc$standard_parameter_checking, 101, clc$optional_parameter, 0, 0],
{ PARAMETER 3
    [1, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation,
  clc$standard_parameter_checking, 3, clc$required_parameter, 0, 0],
{ PARAMETER 4
    [9, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name],
    clc$pass_by_reference, clc$immediate_evaluation,
  clc$standard_parameter_checking, 3, clc$optional_parameter, 0, 0]],
{ PARAMETER 1
    [[1, 0, clc$list_type], [85, 1, clc$max_list_size, 0, FALSE, FALSE],
      [[1, 0, clc$record_type], [2],
      ['FILE                           ', clc$required_field, 3], [[1, 0,
  clc$file_type]],
      ['NEW_FILE_NAME                  ', clc$optional_field, 3], [[1, 0,
  clc$file_type]]
      ]
    ],
{ PARAMETER 2
    [[1, 0, clc$list_type], [85, 1, clc$max_list_size, 0, FALSE, FALSE],
      [[1, 0, clc$record_type], [2],
      ['CATALOG                        ', clc$required_field, 3], [[1, 0,
  clc$file_type]],
      ['NEW_CATALOG_NAME               ', clc$optional_field, 3], [[1, 0,
  clc$file_type]]
      ]
    ],
{ PARAMETER 3
    [[1, 0, clc$file_type]],
{ PARAMETER 4
    [[1, 0, clc$status_type]]];

?? FMT (FORMAT := ON) ??
?? POP ??

    CONST
      p$files = 1,
      p$catalogs = 2,
      p$backup_file = 3,
      p$status = 4;

    VAR
      pvt: array [1 .. 4] of clt$parameter_value;

    VAR
      backup_file: amt$local_file_name,
      backup_file_id: put$file_identifier,
      current_file: ^clt$data_value,
      cycle_selector: pft$cycle_selector,
      cycle_specified: boolean,
      duplicate_cycle_entry: boolean,
      entry_found: boolean,
      evaluated_file_reference: fst$evaluated_file_reference,
      file_field_value_p: ^clt$data_value,
      local_status: ost$status,
      new_cycle_selector: pft$cycle_selector,
      new_cycle_specified: boolean,
      new_file_name_field_value_p: ^clt$data_value,
      new_path_container: clt$path_container,
      p_current_object: ^put$selected_object,
      p_current_pf_object: ^put$selected_object,
      p_new_path: ^pft$path,
      p_path: ^pft$path,
      p_path_string: ^fst$path,
      p_previous_object: ^put$selected_object,
      p_search_object: ^put$selected_object,
      p_selected_objects: ^put$selected_object,
      path_container: clt$path_container,
      path_string_size: fst$path_size,
      requested_subset_found: boolean,
      set_entry: put$entry;

    clp$evaluate_parameters (parameter_list, #SEQ (pdt), NIL, ^pvt, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF (NOT pvt [p$files].specified) AND (NOT pvt [p$catalogs].specified) THEN
      osp$set_status_condition (pue$no_objects_selected, status);
      RETURN; {----->
    IFEND;

    PUSH p_selected_objects;
    p_current_object := p_selected_objects;
    p_current_object^.p_catalog_header := NIL;
    p_current_object^.p_new_catalog_header := NIL;
    p_current_object^.object_restored := FALSE;
    p_current_object^.link := NIL;

    {
    { Process the FILES parameter.
    {

    IF pvt [p$files].specified THEN
      current_file := pvt [p$files].value;

      WHILE (current_file <> NIL) AND (current_file^.element_value <> NIL) DO
        IF p_current_object = NIL THEN
          PUSH p_current_object;
          p_current_object^.p_catalog_header := NIL;
          p_current_object^.p_new_catalog_header := NIL;
          p_current_object^.object_restored := FALSE;
          p_current_object^.link := NIL;
          p_previous_object^.link := p_current_object;
        IFEND;

        file_field_value_p := clf$field_value ('FILE', current_file^.element_value);
        new_file_name_field_value_p := clf$field_value ('NEW_FILE_NAME', current_file^.element_value);
        pup$crack_pf_file_reference (file_field_value_p^.file_value^,
              $put$cycle_reference_selections [puc$cycle_omitted, puc$lowest_cycle, puc$highest_cycle,
              puc$specific_cycle], 'FILE', path_container, p_path, cycle_specified, cycle_selector, status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;

        pup$build_entry (p_path^ [UPPERBOUND (p_path^)], cycle_selector, puc$valid_pf_entry,
              p_current_object^.entry);
        p_current_pf_object := p_current_object;

        PUSH p_current_object^.p_catalog_header: [1 .. UPPERBOUND (p_path^)];
        pup$build_catalog_header (osc$nosve_system_set, p_path, p_current_object^.p_catalog_header^);

        IF new_file_name_field_value_p <> NIL THEN
          pup$crack_pf_file_reference (new_file_name_field_value_p^.file_value^,
                $put$cycle_reference_selections [puc$cycle_omitted, puc$next_highest_cycle,
                puc$specific_cycle], 'FILE', new_path_container, p_new_path, new_cycle_specified,
                new_cycle_selector, status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;

          IF new_cycle_specified THEN
            clp$evaluate_file_reference (new_file_name_field_value_p^.file_value^,
                  $clt$file_ref_parsing_options [], {resolve_cycle_number} TRUE, evaluated_file_reference,
                  status);
            IF NOT status.normal THEN
              RETURN; {----->
            IFEND;
            new_cycle_selector.cycle_option := pfc$specific_cycle;
            new_cycle_selector.cycle_number := evaluated_file_reference.cycle_reference.cycle_number;
            p_current_object^.selected_cycle_info.new_selected_cycle.cycle_specified := TRUE;
            p_current_object^.selected_cycle_info.new_selected_cycle.cycle_selector := new_cycle_selector;
            IF NOT cycle_specified THEN
              cycle_specified := TRUE;
              cycle_selector.cycle_option := pfc$highest_cycle;
            IFEND;
          ELSE
            p_current_object^.selected_cycle_info.new_selected_cycle.cycle_specified := FALSE;
            p_current_object^.p_new_catalog_header := p_current_object^.p_catalog_header;
          IFEND;
          pup$build_entry (p_new_path^ [UPPERBOUND (p_new_path^)], new_cycle_selector, puc$valid_cycle_entry,
                p_current_object^.new_entry);
          PUSH p_current_object^.p_new_catalog_header: [1 .. UPPERBOUND (p_new_path^)];
          pup$build_catalog_header (osc$nosve_system_set, p_new_path,
                p_current_object^.p_new_catalog_header^);
        ELSE
          pup$build_entry (p_path^ [UPPERBOUND (p_path^)], cycle_selector, puc$valid_pf_entry,
                p_current_object^.new_entry);
          PUSH p_current_object^.p_new_catalog_header: [1 .. UPPERBOUND (p_path^)];
          pup$build_catalog_header (osc$nosve_system_set, p_path, p_current_object^.p_new_catalog_header^);
          p_current_object^.selected_cycle_info.new_selected_cycle.cycle_specified := FALSE;
        IFEND;

        IF cycle_specified THEN
          pup$build_entry (p_path^ [UPPERBOUND (p_path^)], cycle_selector, puc$valid_cycle_entry,
                p_current_object^.new_entry);
          p_current_object^.selected_cycle_info.selected_cycle.cycle_specified := TRUE;
          p_current_object^.selected_cycle_info.selected_cycle.cycle_selector := cycle_selector;
          p_previous_object := p_current_object;
          p_current_object := p_current_object^.link;
          IF p_current_object = NIL THEN
            PUSH p_current_object;
            p_current_object^ := p_previous_object^;
            p_previous_object^.link := p_current_object;
          IFEND;
          pup$build_entry (p_path^ [UPPERBOUND (p_path^)], cycle_selector, puc$valid_cycle_entry,
                p_current_object^.entry);
          IF (new_file_name_field_value_p = NIL) THEN
            pup$build_entry (p_path^ [UPPERBOUND (p_path^)], cycle_selector, puc$valid_cycle_entry,
                  p_current_object^.new_entry);
          IFEND;
        ELSE
          pup$build_entry (p_path^ [UPPERBOUND (p_path^)], cycle_selector, puc$valid_pf_entry,
                p_current_object^.new_entry);
          p_current_object^.selected_cycle_info.selected_cycle.cycle_specified := FALSE;
        IFEND;

        p_search_object := p_selected_objects;
        WHILE p_search_object <> NIL DO
          IF NOT ((p_search_object = p_current_pf_object) OR (p_search_object = p_current_object)) THEN
            pup$compare_item_descriptor (p_search_object^.entry, p_search_object^.p_catalog_header^,
                  p_current_object^.entry, p_current_object^.p_catalog_header^, entry_found,
                  requested_subset_found);
            IF entry_found THEN
              duplicate_cycle_entry := same_cycle_specified (p_search_object, p_current_object);
            ELSEIF cycle_specified AND (p_search_object^.entry.entry_type = puc$valid_pf_entry) AND
                  requested_subset_found THEN
              duplicate_cycle_entry := same_cycle_specified (p_search_object, p_current_pf_object);
            ELSEIF (NOT cycle_specified) AND (p_search_object^.entry.entry_type = puc$valid_cycle_entry) THEN
              pup$compare_item_descriptor (p_current_object^.entry, p_current_object^.p_catalog_header^,
                    p_search_object^.entry, p_search_object^.p_catalog_header^, entry_found,
                    requested_subset_found);
              duplicate_cycle_entry := requested_subset_found;
            ELSE
              duplicate_cycle_entry := FALSE;
            IFEND;

            IF duplicate_cycle_entry THEN
              clp$evaluate_file_reference (file_field_value_p^.file_value^, $clt$file_ref_parsing_options [],
                    {resolve_cycle_number} FALSE, evaluated_file_reference, status);
              IF NOT status.normal THEN
                RETURN; {----->
              IFEND;

              PUSH p_path_string;
              clp$convert_file_ref_to_string (evaluated_file_reference, {include_open_position} FALSE,
                    p_path_string^, path_string_size, status);
              IF NOT status.normal THEN
                RETURN; {----->
              IFEND;

              osp$set_status_abnormal (puc$pf_utility_id, pue$redundant_objects_selected, 'file', status);
              osp$append_status_parameter (osc$status_parameter_delimiter,
                    p_path_string^ (1, path_string_size), status);
              RETURN; {----->
            IFEND;
          IFEND;
          p_search_object := p_search_object^.link;
        WHILEND;

        p_previous_object := p_current_object;
        p_current_object := p_current_object^.link;
        current_file := current_file^.link;
      WHILEND;
    IFEND;

    {
    { Process CATALOGS parameter.
    {
    IF pvt [p$catalogs].specified THEN
      current_file := pvt [p$catalogs].value;

      WHILE (current_file <> NIL) AND (current_file^.element_value <> NIL) DO
        IF p_current_object = NIL THEN
          PUSH p_current_object;
          p_current_object^.p_catalog_header := NIL;
          p_current_object^.p_new_catalog_header := NIL;
          p_current_object^.object_restored := FALSE;
          p_current_object^.link := NIL;
          p_previous_object^.link := p_current_object;
        IFEND;

        file_field_value_p := clf$field_value ('CATALOG', current_file^.element_value);
        new_file_name_field_value_p := clf$field_value ('NEW_CATALOG_NAME', current_file^.element_value);
        pup$crack_pf_file_reference (file_field_value_p^.file_value^,
              $put$cycle_reference_selections [puc$cycle_omitted], 'CATALOG', path_container, p_path,
              cycle_specified, cycle_selector, status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;

        pup$build_entry (p_path^ [UPPERBOUND (p_path^)], cycle_selector, puc$valid_catalog_entry,
              p_current_object^.entry);

        PUSH p_current_object^.p_catalog_header: [1 .. UPPERBOUND (p_path^)];
        pup$build_catalog_header (osc$nosve_system_set, p_path, p_current_object^.p_catalog_header^);

        IF new_file_name_field_value_p <> NIL THEN
          pup$crack_pf_file_reference (new_file_name_field_value_p^.file_value^,
                $put$cycle_reference_selections [puc$cycle_omitted], 'CATALOG', path_container, p_path,
                cycle_specified, cycle_selector, status);
          IF NOT status.normal THEN
            RETURN; {----->
          IFEND;

          pup$build_entry (p_path^ [UPPERBOUND (p_path^)], cycle_selector, puc$valid_catalog_entry,
                p_current_object^.new_entry);

          PUSH p_current_object^.p_new_catalog_header: [1 .. UPPERBOUND (p_path^)];
          pup$build_catalog_header (osc$nosve_system_set, p_path, p_current_object^.p_new_catalog_header^);
        ELSE
          p_current_object^.new_entry := p_current_object^.entry;
          p_current_object^.p_new_catalog_header := p_current_object^.p_catalog_header;
        IFEND;

        p_search_object := p_selected_objects;
        WHILE p_search_object <> NIL DO
          IF p_search_object <> p_current_object THEN
            pup$compare_item_descriptor (p_search_object^.entry, p_search_object^.p_catalog_header^,
                  p_current_object^.entry, p_current_object^.p_catalog_header^, entry_found,
                  requested_subset_found);
            IF entry_found THEN
              clp$evaluate_file_reference (file_field_value_p^.file_value^, $clt$file_ref_parsing_options [],
                    {resolve_cycle_number} FALSE, evaluated_file_reference, status);
              IF NOT status.normal THEN
                RETURN; {----->
              IFEND;

              PUSH p_path_string;
              clp$convert_file_ref_to_string (evaluated_file_reference, {include_open_position} FALSE,
                    p_path_string^, path_string_size, status);
              IF NOT status.normal THEN
                RETURN; {----->
              IFEND;

              osp$set_status_abnormal (puc$pf_utility_id, pue$redundant_objects_selected, 'catalog', status);
              osp$append_status_parameter (osc$status_parameter_delimiter,
                    p_path_string^ (1, path_string_size), status);
              RETURN; {----->
            IFEND;
          IFEND;
          p_search_object := p_search_object^.link;
        WHILEND;
        current_file := current_file^.link;
        p_previous_object := p_current_object;
        p_current_object := p_current_object^.link;
      WHILEND;
    IFEND;

    pup$crack_backup_file (pvt [p$backup_file].value^.file_value^, backup_file, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    pup$open_backup_file (backup_file, puc$restore_permanent_files, amc$open_at_boi, backup_file_id, status);
    IF status.normal THEN
      set_entry.entry_type := puc$valid_set_entry;
      set_entry.set_name := osc$nosve_system_set;
      pup$initialize_restore_listing (' RESTORE OBJECT:', p_selected_objects^.p_catalog_header^, set_entry,
            p_selected_objects^.p_catalog_header^.path, cycle_selector, status);
      IF status.normal THEN
        pup$set_restore_subcmd_defaults (NOT (avp$system_administrator () OR avp$family_administrator ()));
        pup$restore_selected_objects (p_selected_objects, backup_file_id, status);
        pup$display_restore_totals;
      IFEND;

      pup$close_backup_file (backup_file_id, local_status);
      IF status.normal THEN
        status := local_status;
      IFEND;
      pup$get_summary_status (status);
    IFEND;

  PROCEND pup$restore_object_command;

  FUNCTION same_cycle_specified
    (    p_search_object: ^put$selected_object;
         p_current_object: ^put$selected_object): boolean;

    IF p_search_object^.selected_cycle_info.selected_cycle.cycle_specified AND
          p_current_object^.selected_cycle_info.selected_cycle.cycle_specified THEN
      CASE p_search_object^.selected_cycle_info.selected_cycle.cycle_selector.cycle_option OF
      = pfc$highest_cycle =
        same_cycle_specified := p_current_object^.selected_cycle_info.selected_cycle.cycle_selector.
              cycle_option = pfc$highest_cycle;
      = pfc$lowest_cycle =
        same_cycle_specified := p_current_object^.selected_cycle_info.selected_cycle.cycle_selector.
              cycle_option = pfc$lowest_cycle;
      = pfc$specific_cycle =
        same_cycle_specified := ((p_current_object^.selected_cycle_info.selected_cycle.cycle_selector.
              cycle_option = pfc$specific_cycle) AND (p_search_object^.selected_cycle_info.selected_cycle.
              cycle_selector.cycle_number = p_current_object^.selected_cycle_info.selected_cycle.
              cycle_selector.cycle_number));
      CASEND;
    ELSE
      same_cycle_specified := TRUE;
    IFEND;

  FUNCEND same_cycle_specified;

MODEND pum$restore_object;
