*copyc osd$default_pragmats
?? RIGHT := 110 ??
?? NEWTITLE := ' NOS/VE Backup/Restore Utilities:  excluded_item_management ', EJECT ??
MODULE pum$excluded_item_management;

?? NEWTITLE := '   Global Declarations', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc pud$hierarchy_list
*copyc pue$error_condition_codes
*copyc put$excluded_item_entry
?? POP ??
*copyc clp$scan_parameter_list
*copyc osp$append_status_integer
*copyc osp$append_status_parameter
*copyc osp$set_status_abnormal
*copyc pfp$get_family_set
*copyc pup$build_catalog_header
*copyc pup$build_entry
*copyc pup$compare_item_descriptor
*copyc pup$compare_paths
*copyc pup$crack_catalog
*copyc pup$crack_permanent_file
*copyc pup$display_item_descriptor
*copyc pup$display_line
*copyc pup$find_cycle_entry
*copyc pup$set_abnormal_entry_status
*copyc pup$verify_catalog_path
*copyc pup$verify_family_administrator
*copyc pup$verify_file_path
*copyc pup$write_path
?? TITLE := '    Global Variables', EJECT ??

  VAR
    excluded_item_list: put$excluded_item_list := [REP 6 of NIL];

?? TITLE := '    [XDCL] pup$check_if_item_excluded ', EJECT ??

  PROCEDURE [XDCL] pup$check_if_item_excluded (entry: put$entry;
        catalog_header: put$catalog_header;
    VAR item_excluded: boolean);

    pup$search_item_list (entry, catalog_header, excluded_item_list [entry.entry_type], item_excluded);
  PROCEND pup$check_if_item_excluded;

?? TITLE := '    [XDCL] pup$check_if_subitem_excluded ', EJECT ??

  PROCEDURE [XDCL] pup$check_if_subitem_excluded (catalog_header: put$catalog_header;
    VAR subitem_excluded: boolean);

  {This procedure determines whether a catlog contains files or subcatalogs that
  {have been excluded by BACPF EXCLUDE_FILE or EXCLUDE_CATALOG subcommands.

    VAR
      entry_type: put$entry_type,
      ignore_a_equals_b: boolean,
      p_item_entry: ^put$excluded_item_entry;

    subitem_excluded := FALSE;
    FOR entry_type := puc$valid_catalog_entry TO puc$valid_cycle_entry DO
      p_item_entry :=  excluded_item_list [entry_type];
      WHILE (p_item_entry <> NIL) DO
        pup$compare_paths (catalog_header.path, p_item_entry^.catalog_header.path, ignore_a_equals_b,
              subitem_excluded);
        IF NOT subitem_excluded THEN
          p_item_entry := p_item_entry^.p_next_excluded_entry;
        ELSE
          RETURN;
        IFEND;
      WHILEND;
    FOREND;
  PROCEND pup$check_if_subitem_excluded;

?? TITLE := '    [XDCL] pup$display_excluded_items ', EJECT ??

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

{ PDT display_excluded_pdt (status)

?? PUSH (LISTEXT := ON) ??

    VAR
      display_excluded_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table :=
        [^display_excluded_pdt_names, ^display_excluded_pdt_params];

    VAR
      display_excluded_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 1] of
        clt$parameter_name_descriptor := [['STATUS', 1]];

    VAR
      display_excluded_pdt_params: [STATIC, READ, cls$pdt_parameters] array [1 .. 1] of
        clt$parameter_descriptor := [

{ STATUS }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$variable_reference,
        clc$array_not_allowed, clc$status_value]]];

?? POP ??

    VAR
      entry_type: put$entry_type,
      item_found_excluded: boolean,
      p_item_entry: ^put$excluded_item_entry;

    clp$scan_parameter_list (parameter_list, display_excluded_pdt, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    item_found_excluded := FALSE;
    FOR entry_type := puc$valid_family_entry TO puc$valid_cycle_entry DO
      p_item_entry := excluded_item_list [entry_type];
      IF p_item_entry <> NIL THEN
        item_found_excluded := TRUE;
        CASE entry_type OF
        = puc$valid_family_entry, puc$valid_catalog_entry =
          pup$display_line (' EXCLUDED_CATALOGS ----', status);
        = puc$valid_pf_entry =
          pup$display_line (' EXCLUDED PERMANENT FILES ----', status);
        ELSE
          pup$display_line (' EXCLUDED CYCLES ----', status);
        CASEND;
        WHILE p_item_entry <> NIL DO
          pup$display_item_descriptor ('----', p_item_entry^.catalog_header, p_item_entry^.entry, status);
          p_item_entry := p_item_entry^.p_next_excluded_entry;
        WHILEND;
      IFEND;
    FOREND;
    IF NOT item_found_excluded THEN
      pup$display_line (' ALL CATALOGS, AND FILES INCLUDED', status);
    IFEND;
  PROCEND pup$display_excluded_items;


?? TITLE := '    [XDCL] pup$exclude_catalog_command ', EJECT ??

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

{ PDT exclude_catalog_pdt (
{  catalog,c: file = $REQUIRED
{  status)

?? PUSH (LISTEXT := ON) ??

    VAR
      exclude_catalog_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table :=
        [^exclude_catalog_pdt_names, ^exclude_catalog_pdt_params];

    VAR
      exclude_catalog_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 3] of
        clt$parameter_name_descriptor := [['CATALOG', 1], ['C', 1], ['STATUS', 2]];

    VAR
      exclude_catalog_pdt_params: [STATIC, READ, cls$pdt_parameters] array [1 .. 2] of
        clt$parameter_descriptor := [

{ CATALOG C }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$file_value]],

{ STATUS }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$variable_reference,
        clc$array_not_allowed, clc$status_value]]];

?? POP ??

    VAR
      catalog_path_container: clt$path_container,
      dummy_cycle_selector: pft$cycle_selector,
      entry: put$entry,
      entry_type: put$entry_type,
      p_catalog_header: ^put$catalog_header,
      p_catalog_path: ^pft$path,
      set_name: stt$set_name;

    clp$scan_parameter_list (parameter_list, exclude_catalog_pdt, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pup$crack_catalog ('CATALOG', catalog_path_container, p_catalog_path, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pup$verify_catalog_path (p_catalog_path^, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF UPPERBOUND (p_catalog_path^) = pfc$family_name_index THEN
      entry_type := puc$valid_family_entry;
      pup$verify_family_administrator (' EXCLUDE_CATALOG', p_catalog_path^ [UPPERBOUND (p_catalog_path^)],
            status);
      IF NOT status.normal THEN
        osp$append_status_parameter (osc$status_parameter_delimiter, ' to exclude a family ', status);
        RETURN;
      IFEND;
    ELSE
      entry_type := puc$valid_catalog_entry;
    IFEND;


    pfp$get_family_set (p_catalog_path^ [pfc$family_name_index], set_name, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pup$build_entry (p_catalog_path^ [UPPERBOUND (p_catalog_path^)], dummy_cycle_selector,
          entry_type, entry);
    PUSH p_catalog_header: [1 .. UPPERBOUND (p_catalog_path^)];
    pup$build_catalog_header (set_name, p_catalog_path, p_catalog_header^);
    exclude_item (entry, p_catalog_header^, status);
    IF status.normal THEN
      pup$display_item_descriptor (' EXCLUDE_CATALOG ', p_catalog_header^, entry, status);
    IFEND;
  PROCEND pup$exclude_catalog_command;


?? TITLE := '    [XDCL] pup$exclude_pf_command ', EJECT ??

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

{ PDT exclude_pf_pdt (
{  file, f: file = $required
{  status)

?? PUSH (LISTEXT := ON) ??

    VAR
      exclude_pf_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^exclude_pf_pdt_names,
        ^exclude_pf_pdt_params];

    VAR
      exclude_pf_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 3] of
        clt$parameter_name_descriptor := [['FILE', 1], ['F', 1], ['STATUS', 2]];

    VAR
      exclude_pf_pdt_params: [STATIC, READ, cls$pdt_parameters] array [1 .. 2] of clt$parameter_descriptor :=
        [

{ FILE F }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$file_value]],

{ STATUS }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$variable_reference,
        clc$array_not_allowed, clc$status_value]]];

?? POP ??

    VAR
      cycle_array_entry: pft$cycle_array_entry_version_2,
      cycle_selector: pft$cycle_selector,
      cycle_selector_specified: boolean,
      entry: put$entry,
      p_catalog_header: ^put$catalog_header,
      p_pf_path: ^pft$path,
      pf_path_container: clt$path_container,
      set_name: stt$set_name;

    clp$scan_parameter_list (parameter_list, exclude_pf_pdt, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pup$crack_permanent_file ('FILE', $put$cycle_reference_selections [puc$cycle_omitted, puc$specific_cycle,
          puc$highest_cycle, puc$lowest_cycle], pf_path_container, p_pf_path, cycle_selector_specified,
          cycle_selector, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF cycle_selector_specified THEN
      pup$find_cycle_entry (p_pf_path^, cycle_selector, cycle_array_entry, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      cycle_selector.cycle_option := pfc$specific_cycle;
      cycle_selector.cycle_number := cycle_array_entry.cycle_number;
      pup$build_entry (p_pf_path^ [UPPERBOUND (p_pf_path^)], cycle_selector, puc$valid_cycle_entry, entry);
    ELSE { permanent file path
      pup$verify_file_path (p_pf_path^, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      pup$build_entry (p_pf_path^ [UPPERBOUND (p_pf_path^)], cycle_selector, puc$valid_pf_entry, entry);
    IFEND;

    pfp$get_family_set (p_pf_path^ [pfc$family_name_index], set_name, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    PUSH p_catalog_header: [1 .. UPPERBOUND (p_pf_path^)];
    pup$build_catalog_header (set_name, p_pf_path, p_catalog_header^);
    exclude_item (entry, p_catalog_header^, status);
    IF status.normal THEN
      pup$display_item_descriptor (' EXCLUDE_PERMANENT_FILE ', p_catalog_header^, entry, status);
    IFEND;
  PROCEND pup$exclude_pf_command;

?? TITLE := '    [XDCL] pup$include_catalog_command ', EJECT ??

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

{ PDT include_catalog_pdt (
{  catalog,c: file = $REQUIRED
{  status)

?? PUSH (LISTEXT := ON) ??

    VAR
      include_catalog_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table :=
        [^include_catalog_pdt_names, ^include_catalog_pdt_params];

    VAR
      include_catalog_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 3] of
        clt$parameter_name_descriptor := [['CATALOG', 1], ['C', 1], ['STATUS', 2]];

    VAR
      include_catalog_pdt_params: [STATIC, READ, cls$pdt_parameters] array [1 .. 2] of
        clt$parameter_descriptor := [

{ CATALOG C }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$file_value]],

{ STATUS }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$variable_reference,
        clc$array_not_allowed, clc$status_value]]];

?? POP ??

    VAR
      catalog_path_container: clt$path_container,
      dummy_cycle_selector: pft$cycle_selector,
      entry: put$entry,
      entry_type: put$entry_type,
      p_catalog_header: ^put$catalog_header,
      p_catalog_path: ^pft$path,
      set_name: stt$set_name;


    clp$scan_parameter_list (parameter_list, include_catalog_pdt, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pup$crack_catalog ('CATALOG', catalog_path_container, p_catalog_path, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;


    pfp$get_family_set (p_catalog_path^ [pfc$family_name_index], set_name, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF UPPERBOUND (p_catalog_path^) = pfc$family_name_index THEN
      entry_type := puc$valid_family_entry;
    ELSE
      entry_type := puc$valid_catalog_entry;
    IFEND;
    pup$build_entry (p_catalog_path^ [UPPERBOUND (p_catalog_path^)], dummy_cycle_selector,
          entry_type, entry);
    PUSH p_catalog_header: [1 .. UPPERBOUND (p_catalog_path^)];
    pup$build_catalog_header (set_name, p_catalog_path, p_catalog_header^);
    include_item (entry, p_catalog_header^, status);
    IF status.normal THEN
      pup$display_item_descriptor (' INCLUDE_CATALOG ', p_catalog_header^, entry, status);
    IFEND;
  PROCEND pup$include_catalog_command;

?? TITLE := '    [XDCL] pup$include_excluded_items ', EJECT ??

  PROCEDURE [XDCL] pup$include_excluded_items (parameter_list: clt$parameter_list;
    VAR status: ost$status);
{ PDT include_exc_items_pdt (status)

?? PUSH (LISTEXT := ON) ??

    VAR
      include_exc_items_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table :=
        [^include_exc_items_pdt_names, ^include_exc_items_pdt_params];

    VAR
      include_exc_items_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 1] of
        clt$parameter_name_descriptor := [['STATUS', 1]];

    VAR
      include_exc_items_pdt_params: [STATIC, READ, cls$pdt_parameters] array [1 .. 1] of
        clt$parameter_descriptor := [

{ STATUS }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$variable_reference,
        clc$array_not_allowed, clc$status_value]]];

?? POP ??

    VAR
      entry_kind: put$entry_type;

    clp$scan_parameter_list (parameter_list, include_exc_items_pdt, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    FOR entry_kind := LOWERBOUND (excluded_item_list) TO UPPERBOUND (excluded_item_list) DO
      delete_all_items (excluded_item_list [entry_kind]);
    FOREND;
    pup$display_line (' ALL FILES INCLUDED ', status);
  PROCEND pup$include_excluded_items;

?? TITLE := '    [XDCL] pup$include_pf_command ', EJECT ??

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

{ PDT include_pf_pdt (
{  file, f: file = $required
{  status)

?? PUSH (LISTEXT := ON) ??

    VAR
      include_pf_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^include_pf_pdt_names,
        ^include_pf_pdt_params];

    VAR
      include_pf_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 3] of
        clt$parameter_name_descriptor := [['FILE', 1], ['F', 1], ['STATUS', 2]];

    VAR
      include_pf_pdt_params: [STATIC, READ, cls$pdt_parameters] array [1 .. 2] of clt$parameter_descriptor :=
        [

{ FILE F }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$file_value]],

{ STATUS }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$variable_reference,
        clc$array_not_allowed, clc$status_value]]];

?? POP ??

    VAR
      cycle_selector: pft$cycle_selector,
      cycle_selector_specified: boolean,
      entry: put$entry,
      p_catalog_header: ^put$catalog_header,
      p_pf_path: ^pft$path,
      pf_path_container: clt$path_container,
      set_name: stt$set_name;


    clp$scan_parameter_list (parameter_list, include_pf_pdt, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pup$crack_permanent_file ('FILE', $put$cycle_reference_selections [puc$cycle_omitted, puc$specific_cycle],
          pf_path_container, p_pf_path, cycle_selector_specified, cycle_selector, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF cycle_selector_specified THEN
      pup$build_entry (p_pf_path^ [UPPERBOUND (p_pf_path^)], cycle_selector, puc$valid_cycle_entry, entry);
    ELSE { permanent file path
      pup$build_entry (p_pf_path^ [UPPERBOUND (p_pf_path^)], cycle_selector, puc$valid_pf_entry, entry);
    IFEND;

    pfp$get_family_set (p_pf_path^ [pfc$family_name_index], set_name, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    PUSH p_catalog_header: [1 .. UPPERBOUND (p_pf_path^)];
    pup$build_catalog_header (set_name, p_pf_path, p_catalog_header^);
    include_item (entry, p_catalog_header^, status);
    IF status.normal THEN
      pup$display_item_descriptor (' INCLUDE_PERMANENT_FILE ', p_catalog_header^, entry, status);
    IFEND;
  PROCEND pup$include_pf_command;

?? TITLE := '    pup$search_item_list ', EJECT ??

  PROCEDURE pup$search_item_list (entry: put$entry;
        catalog_header: put$catalog_header;
        p_root: ^put$excluded_item_entry;
    VAR item_found: boolean);

    VAR
      a_above_b: boolean,
      p_item_entry: ^put$excluded_item_entry;

    item_found := FALSE;
    p_item_entry := p_root;
    WHILE (p_item_entry <> NIL) AND (NOT item_found) DO
      pup$compare_item_descriptor (entry, catalog_header, p_item_entry^.entry, p_item_entry^.catalog_header,
            item_found, a_above_b);
      IF NOT item_found THEN
        p_item_entry := p_item_entry^.p_next_excluded_entry;
      IFEND;
    WHILEND;
  PROCEND pup$search_item_list;

?? TITLE := '    delete_all_items ', EJECT ??

  PROCEDURE delete_all_items (VAR p_root: ^put$excluded_item_entry);

    VAR
      p_next_item: ^put$excluded_item_entry;

    WHILE p_root <> NIL DO
      p_next_item := p_root^.p_next_excluded_entry;
      FREE p_root;
      p_root := p_next_item;
    WHILEND;
  PROCEND delete_all_items;

?? TITLE := '    delete_item ', EJECT ??

  PROCEDURE delete_item (entry: put$entry;
        catalog_header: put$catalog_header;
    VAR p_root: ^put$excluded_item_entry;
    VAR deleted_entry: boolean);

    VAR
      a_above_b: boolean,
      p_item_entry: ^put$excluded_item_entry,
      p_previous_entry_pointer: ^^put$excluded_item_entry;

    deleted_entry := FALSE;
    p_item_entry := p_root;
    p_previous_entry_pointer := ^p_root;
    WHILE (p_item_entry <> NIL) AND (NOT deleted_entry) DO
      pup$compare_item_descriptor (entry, catalog_header, p_item_entry^.entry, p_item_entry^.catalog_header,
            deleted_entry, a_above_b);
      IF deleted_entry THEN
        p_previous_entry_pointer^ := p_item_entry^.p_next_excluded_entry;
        FREE p_item_entry;
      ELSE
        p_previous_entry_pointer := ^p_item_entry^.p_next_excluded_entry;
        p_item_entry := p_item_entry^.p_next_excluded_entry;
      IFEND;
    WHILEND;
  PROCEND delete_item;

?? TITLE := '    exclude_item ', EJECT ??

  PROCEDURE exclude_item (entry: put$entry;
        catalog_header: put$catalog_header;
    VAR status: ost$status);

    VAR
      item_found: boolean;

    pup$search_item_list (entry, catalog_header, excluded_item_list [entry.entry_type], item_found);
    IF item_found THEN
      pup$set_abnormal_entry_status (entry, pue$item_already_excluded, status);
    ELSE
      insert_item (entry, catalog_header, excluded_item_list [entry.entry_type]);
      status.normal := TRUE;
    IFEND;
  PROCEND exclude_item;


?? TITLE := '    include_item ', EJECT ??

  PROCEDURE include_item (entry: put$entry;
        catalog_header: put$catalog_header;
    VAR status: ost$status);

    VAR
      item_found: boolean;

    status.normal := TRUE;
    delete_item (entry, catalog_header, excluded_item_list [entry.entry_type], item_found);
    IF NOT item_found THEN
      pup$set_abnormal_entry_status (entry, pue$item_never_excluded, status);
    IFEND;
  PROCEND include_item;

?? TITLE := '    insert_item ', EJECT ??

  PROCEDURE insert_item (entry: put$entry;
        catalog_header: put$catalog_header;
    VAR p_root: ^put$excluded_item_entry);

    VAR
      p_old_root: ^put$excluded_item_entry;

    p_old_root := p_root;
    ALLOCATE p_root: [1 .. UPPERBOUND (catalog_header.path)];
    p_root^.entry := entry;
    p_root^.catalog_header := catalog_header;
    p_root^.p_next_excluded_entry := p_old_root;
  PROCEND insert_item;

MODEND pum$excluded_item_management;
