?? RIGHT := 110 ??
*copyc osd$default_pragmats
?? NEWTITLE := ' NOS/VE Backup/Restore Utilities:  change_all_permits ', EJECT ??
MODULE pum$change_all_permits;
{
{   The purpose of this module is to allow changing all permits in the system,
{   family, catalog, or file.
{   Currently, this only supports changing the family name in the permits.
{   This is required when the family name has been changed via the
{   CHANGE_FAMILY command,  or the family was restored to a different
{   family with RESTORE_CATALOG.
{   All permits, regardless of group, that contain the specified family name
{   will be changed.
{   These commands only work for the system or family administrator, catalog or
{   file owner.
{
?? NEWTITLE := '   Global Declarations', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc clt$parameter_list
*copyc cld$path_description
*copyc clt$value
*copyc pud$hierarchy_list
*copyc pue$error_condition_codes
*copyc clt$parsed_path
*copyc ost$name
*copyc ost$status
*copyc put$user_range_list
?? POP ??
*copyc clp$get_value
*copyc clp$scan_parameter_list
*copyc mmp$create_scratch_segment
*copyc mmp$delete_scratch_segment
*copyc osp$append_status_parameter
*copyc osp$set_status_abnormal
*copyc pfp$delete_catalog_permit
*copyc pfp$delete_permit
*copyc pfp$find_direct_info_record
*copyc pfp$find_directory_array
*copyc pfp$find_next_info_record
*copyc pfp$find_permit_array
*copyc pfp$get_family_info
*copyc pfp$get_family_set
*copyc pfp$get_item_info
*copyc pfp$get_master_catalog_info
*copyc pfp$get_multi_item_info
*copyc pfp$get_set_list
*copyc pfp$permit
*copyc pfp$permit_catalog
*copyc pup$build_catalog_header
*copyc pup$build_entry
*copyc pup$build_new_path
*copyc pup$check_if_family_in_range
*copyc pup$check_if_item_excluded
*copyc pup$check_if_user_in_range
*copyc pup$crack_catalog
*copyc pup$crack_permanent_file
*copyc pup$display_blank_lines
*copyc pup$display_excluded_item
*copyc pup$display_integer
*copyc pup$display_line
*copyc pup$get_summary_status
*copyc pup$initialize_summary_status
*copyc pup$sort_directory
*copyc pup$verify_family_administrator
*copyc pup$verify_system_administrator
*copyc pup$write_os_status
*copyc pup$write_path
*copyc puv$p_user_range_list
*copyc puv$sort_users
*copyc puv$trace_selected
?? TITLE := '    Global Variables', EJECT ??

  VAR
    total_catalog_permits_changed: integer := 0,
    total_file_permits_changed: integer := 0;

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

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


{  pdt change_all_permits_pdt (
{    family_name, fn: name = $required
{    new_family_name, nfn: name = $required
{   status)

?? PUSH (LISTEXT := ON) ??

    VAR
      change_all_permits_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table :=
        [^change_all_permits_pdt_names, ^change_all_permits_pdt_params];

    VAR
      change_all_permits_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 5] of
        clt$parameter_name_descriptor := [['FAMILY_NAME', 1], ['FN', 1], ['NEW_FAMILY_NAME', 2], ['NFN', 2],
        ['STATUS', 3]];

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

{ FAMILY_NAME FN }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ NEW_FAMILY_NAME NFN }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ 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
      local_status: ost$status,
      new_permit_family: pft$name,
      set_list: ^stt$set_list,
      cset,
      number_of_sets: stt$number_of_sets,
      old_permit_family: pft$name;

    pup$verify_system_administrator ('CHANGE_ALL_PERMITS             ', puv$p_user_range_list, status);
    IF NOT status.normal THEN
      IF status.condition = pue$unowned_users_included THEN
        osp$set_status_abnormal (puc$pf_utility_id, pue$not_system_administrator,
              'CHANGE_ALL_PERMITS', status);
      IFEND;
      RETURN;
    IFEND;

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

    crack_family_names (old_permit_family, new_permit_family, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pup$display_line (' CHANGE_ALL_PERMITS ', status);
    pup$display_line (old_permit_family, status);
    pup$display_line (new_permit_family, status);

    pup$initialize_summary_status;
    total_catalog_permits_changed := 0;
    total_file_permits_changed := 0;

    number_of_sets := 20;
    FOR cset := 1 TO 2 DO
      PUSH set_list: [1 .. number_of_sets];
      pfp$get_set_list (set_list^, number_of_sets, status);
    FOREND;
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    FOR cset := 1 TO number_of_sets DO
      pup$change_set_permits (set_list^ [cset], old_permit_family, new_permit_family, status);
    FOREND;

    display_change_permit_totals;
    pup$get_summary_status (status);
    pup$write_os_status (status, local_status);
  PROCEND pup$change_all_permits_cm;
?? TITLE := '    pup$change_set_permits ', EJECT ??

  PROCEDURE pup$change_set_permits (set_name: stt$set_name;
        old_permit_family: pft$name;
        new_permit_family: pft$name;
    VAR status: ost$status);

    VAR
      dummy_cycle_selector: pft$cycle_selector,
      family_entry: put$entry,
      family_excluded: boolean,
      family_in_range: boolean,
      family_info: amt$segment_pointer,
      family_path: array [1 .. 1] of pft$name,
      i: put$half_integer,
      local_status: ost$status,
      p_family_catalog_header: ^put$catalog_header,
      p_family_directory: pft$p_directory_array,
      p_info_record: pft$p_info_record;

    status.normal := TRUE;
    local_status.normal := TRUE;
    mmp$create_scratch_segment (amc$sequence_pointer, mmc$as_random, family_info, status);
    IF status.normal THEN
      RESET family_info.sequence_pointer;
      pfp$get_family_info (set_name, $pft$catalog_info_selections [pfc$catalog_directory], family_info.
            sequence_pointer, status);
      IF status.normal THEN
        RESET family_info.sequence_pointer;
        pfp$find_next_info_record (family_info.sequence_pointer, p_info_record, status);
        IF status.normal THEN
          pfp$find_directory_array (p_info_record, p_family_directory, status);
          IF status.normal AND (p_family_directory <> NIL) THEN
            PUSH p_family_catalog_header: [1 .. 1];

          /process_families/
            FOR i := LOWERBOUND (p_family_directory^) TO UPPERBOUND (p_family_directory^) DO
              pup$check_if_family_in_range (p_family_directory^ [i].name, family_in_range);
              IF family_in_range THEN
                family_path [pfc$family_name_index] := p_family_directory^ [i].name;
                pup$build_entry (p_family_directory^ [i].name, dummy_cycle_selector, puc$valid_family_entry,
                      family_entry);
                pup$build_catalog_header (set_name, ^family_path, p_family_catalog_header^);
                pup$check_if_item_excluded (family_entry, p_family_catalog_header^, family_excluded);
                IF family_excluded THEN
                  pup$display_excluded_item (family_entry, p_family_catalog_header^, status);
                ELSE
                  pup$change_family_permits (set_name, p_family_directory^ [i].name, old_permit_family,
                        new_permit_family, status);
                IFEND;
              IFEND;
            FOREND /process_families/;
          IFEND;
        IFEND;
      IFEND;
      mmp$delete_scratch_segment (family_info, local_status);
    IFEND;
  PROCEND pup$change_set_permits;
?? TITLE := '    pup$change_family_permits ', EJECT ??

{  This procedure assumes there are not permits at the family level, and
{  only changes the permits on each master catalog.

  PROCEDURE pup$change_family_permits (set_name: stt$set_name;
        family_name: pft$name;
        old_permit_family: pft$name;
        new_permit_family: pft$name;
    VAR status: ost$status);

    VAR
      dummy_cycle_selector: pft$cycle_selector,
      entry: put$entry,
      family_content_info: amt$segment_pointer,
      i: put$half_integer,
      local_status: ost$status,
      p_family_content: pft$p_info_record,
      p_master_catalog_directory: pft$p_directory_array,
      p_permit_array: pft$p_permit_array,
      p_user_catalog_header: ^put$catalog_header,
      p_user_record: pft$p_info_record,
      user_excluded: boolean,
      user_in_range: boolean,
      user_path: array [1 .. 2] of pft$name;

    user_path [pfc$family_name_index] := family_name;
    mmp$create_scratch_segment (amc$sequence_pointer, mmc$as_random, family_content_info, status);
    IF status.normal THEN
      RESET family_content_info.sequence_pointer;
      pfp$get_master_catalog_info (set_name, family_name, $pft$catalog_info_selections [pfc$catalog_directory,
            pfc$catalog_permits], family_content_info.sequence_pointer, status);
      IF status.normal THEN
        RESET family_content_info.sequence_pointer;
        pfp$find_next_info_record (family_content_info.sequence_pointer, p_family_content, status);
        IF status.normal THEN
          pfp$find_directory_array (p_family_content, p_master_catalog_directory, status);
          IF status.normal AND (p_master_catalog_directory <> NIL) THEN
            IF puv$sort_users THEN
              pup$sort_directory (p_master_catalog_directory^, p_master_catalog_directory^);
            IFEND;
            PUSH p_user_catalog_header: [1 .. 2];

          /change_users/
            FOR i := LOWERBOUND (p_master_catalog_directory^) TO UPPERBOUND (p_master_catalog_directory^) DO
              pup$check_if_user_in_range (family_name, p_master_catalog_directory^ [i].name, user_in_range);
              IF user_in_range THEN
                user_path [pfc$master_catalog_name_index] := p_master_catalog_directory^ [i].name;
                pup$build_entry (user_path [pfc$master_catalog_name_index], dummy_cycle_selector,
                      puc$valid_catalog_entry, entry);
                pup$build_catalog_header (set_name, ^user_path, p_user_catalog_header^);
                pup$check_if_item_excluded (entry, p_user_catalog_header^, user_excluded);
                IF user_excluded THEN
                  pup$display_excluded_item (entry, p_user_catalog_header^, status);
                ELSE
                  pfp$find_direct_info_record (^p_family_content^.body, p_master_catalog_directory^ [i].
                        info_offset, p_user_record, status);
                  IF status.normal THEN
                    pfp$find_permit_array (p_user_record, p_permit_array, status);
                    IF status.normal THEN
                      change_catalog_permits (user_path, p_permit_array, old_permit_family, new_permit_family,
                            status);
                      IF NOT status.normal THEN
                        pup$write_os_status (status, status);
                      IFEND;
                      change_catalog_content_permits (user_path, old_permit_family, new_permit_family,
                            status);
                    IFEND;
                  IFEND;
                  pup$write_os_status (status, status);
                IFEND;
              IFEND;
            FOREND /change_users/;
          IFEND;
        IFEND;
      IFEND;
      mmp$delete_scratch_segment (family_content_info, local_status);
    IFEND;
  PROCEND pup$change_family_permits;
?? TITLE := '    [XDCL] pup$change_catalog_permits_cm ', EJECT ??

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

{  PDT change_cat_permits_pdt (
{     catalog, c: file = $required
{     family_name, fn: name = $required
{     new_family_name, nfn: name = $required
{  status)

?? PUSH (LISTEXT := ON) ??

    VAR
      change_cat_permits_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table :=
        [^change_cat_permits_pdt_names, ^change_cat_permits_pdt_params];

    VAR
      change_cat_permits_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 7] of
        clt$parameter_name_descriptor := [['CATALOG', 1], ['C', 1], ['FAMILY_NAME', 2], ['FN', 2], [
        'NEW_FAMILY_NAME', 3], ['NFN', 3], ['STATUS', 4]];

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

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

{ FAMILY_NAME FN }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ NEW_FAMILY_NAME NFN }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ 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
      local_status: ost$status,
      new_permit_family: pft$name,
      old_permit_family: pft$name,
      p_path: ^pft$path,
      path_container: clt$path_container,
      set_name: stt$set_name;

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

    pup$crack_catalog ('CATALOG', path_container, p_path, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    IF UPPERBOUND (p_path^) = pfc$family_name_index THEN
      pup$verify_family_administrator ('CHANGE_CATALOG_PERMITS', p_path^ [pfc$family_name_index], status);
      IF NOT status.normal THEN
        osp$append_status_parameter (osc$status_parameter_delimiter, ' to change a family', status);
        RETURN;
      IFEND;
    IFEND;

    crack_family_names (old_permit_family, new_permit_family, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pup$display_line (' CHANGE_CATALOG_PERMITS', status);
    pup$write_path (p_path^, status);
    pup$display_line (old_permit_family, status);
    pup$display_line (new_permit_family, status);

    total_catalog_permits_changed := 0;
    total_file_permits_changed := 0;
    pup$initialize_summary_status;

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

      pup$change_family_permits (set_name, p_path^ [pfc$family_name_index], old_permit_family,
            new_permit_family, status);
    ELSE
      pup$change_catalog_permits (p_path^, old_permit_family, new_permit_family, status);
    IFEND;

    display_change_permit_totals;
    pup$get_summary_status (status);
    pup$write_os_status (status, local_status);
  PROCEND pup$change_catalog_permits_cm;
?? TITLE := '    pup$change_catalog_permits ', EJECT ??

  PROCEDURE pup$change_catalog_permits (path: pft$path;
        old_permit_family: pft$name;
        new_permit_family: pft$name;
    VAR status: ost$status);

    VAR
      catalog_info: amt$segment_pointer,
      entry: put$entry,
      index: integer,
      group: pft$group,
      local_status: ost$status,
      p_catalog_header: ^put$catalog_header,
      p_directory_array: pft$p_directory_array,
      p_info_record: pft$p_info_record,
      p_permit_array: pft$p_permit_array,
      set_name: stt$set_name;

    status.normal := TRUE;
    PUSH p_catalog_header: [1 .. UPPERBOUND (path)];

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

    pup$build_catalog_header (set_name, ^path, p_catalog_header^);
    IF status.normal THEN
      mmp$create_scratch_segment (amc$sequence_pointer, mmc$as_random, catalog_info, status);
    IFEND;
    IF status.normal THEN
      RESET catalog_info.sequence_pointer;
      group.group_type := pfc$public;
      pfp$get_item_info (path, group, $pft$catalog_info_selections [pfc$catalog_directory,
            pfc$catalog_permits], $pft$file_info_selections [], catalog_info.sequence_pointer, status);
      IF status.normal THEN
        RESET catalog_info.sequence_pointer;
        pfp$find_next_info_record (catalog_info.sequence_pointer, p_info_record, status);
        IF status.normal THEN
          pfp$find_directory_array (p_info_record, p_directory_array, status);
          IF p_directory_array <> NIL THEN
            pfp$find_direct_info_record (^p_info_record^.body, p_directory_array^ [1].info_offset,
                  p_info_record, status);
            IF status.normal THEN
              pfp$find_permit_array (p_info_record, p_permit_array, status);
              IF status.normal THEN
                change_catalog_permits (path, p_permit_array, old_permit_family, new_permit_family, status);
              IFEND;
              pup$write_os_status (status, local_status);
            IFEND;
          IFEND;
        IFEND;
      IFEND;
      mmp$delete_scratch_segment (catalog_info, local_status);
    IFEND;
    change_catalog_content_permits (path, old_permit_family, new_permit_family, status);
  PROCEND pup$change_catalog_permits;

?? TITLE := '    change_catalog_content_permits ', EJECT ??

{ This procedure assumes that the permit for the catalog has already been changed.
{ This routine will change the permits associated will all subcatalogs,
{ and files within the specified catalog.

  PROCEDURE change_catalog_content_permits (path: pft$path;
        old_permit_family: pft$name;
        new_permit_family: pft$name;
    VAR status: ost$status);

    VAR
      catalog_content_info: amt$segment_pointer,
      dummy_cycle_selector: pft$cycle_selector,
      entry: put$entry,
      group: pft$group,
      index: integer,
      item_excluded: boolean,
      local_status: ost$status,
      p_catalog_header: ^put$catalog_header,
      p_catalog_info: pft$p_info_record,
      p_directory_array: pft$p_directory_array,
      p_file_info: pft$p_info_record,
      p_info_record: pft$p_info_record,
      p_new_path: ^pft$path,
      p_permit_array: pft$p_permit_array,
      set_name: stt$set_name;


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

    mmp$create_scratch_segment (amc$sequence_pointer, mmc$as_random, catalog_content_info, status);
    IF status.normal THEN
      RESET catalog_content_info.sequence_pointer;
      group.group_type := pfc$public;
      pfp$get_multi_item_info (path, group, $pft$catalog_info_selections [pfc$catalog_directory,
            pfc$catalog_permits], $pft$file_info_selections [pfc$file_directory, pfc$file_permits],
            catalog_content_info.sequence_pointer, status);
      IF status.normal THEN
        RESET catalog_content_info.sequence_pointer;
        pfp$find_next_info_record (catalog_content_info.sequence_pointer, p_info_record, status);
        IF status.normal THEN
          pfp$find_directory_array (p_info_record, p_directory_array, status);
          IF status.normal AND (p_directory_array <> NIL) THEN
            PUSH p_catalog_header: [1 .. UPPERBOUND (path) + 1];
            PUSH p_new_path: [1 .. (UPPERBOUND (path) + 1)];

          /change_files/
            FOR index := LOWERBOUND (p_directory_array^) TO UPPERBOUND (p_directory_array^) DO
              CASE p_directory_array^ [index].name_type OF
              = pfc$file_name =
                pup$build_new_path (path, p_directory_array^ [index].name, p_new_path^);
                pup$build_catalog_header (set_name, p_new_path, p_catalog_header^);
                pup$build_entry (p_directory_array^ [index].name, dummy_cycle_selector, puc$valid_pf_entry,
                      entry);
                pup$check_if_item_excluded (entry, p_catalog_header^, item_excluded);
                IF item_excluded THEN
                  pup$display_excluded_item (entry, p_catalog_header^, status);
                ELSE
                  pfp$find_direct_info_record (^p_info_record^.body, p_directory_array^ [index].info_offset,
                        p_file_info, status);
                  IF status.normal THEN
                    pfp$find_permit_array (p_file_info, p_permit_array, status);
                    IF status.normal THEN
                      change_file_permits (p_new_path^, p_permit_array, old_permit_family, new_permit_family,
                            status);
                    IFEND;
                  IFEND;
                  pup$write_os_status (status, local_status);
                  status.normal := TRUE;
                IFEND;
              ELSE
              CASEND;
            FOREND /change_files/;

          /change_catalogs/
            FOR index := LOWERBOUND (p_directory_array^) TO UPPERBOUND (p_directory_array^) DO

              CASE p_directory_array^ [index].name_type OF
              = pfc$catalog_name =
                pup$build_new_path (path, p_directory_array^ [index].name, p_new_path^);
                pup$build_catalog_header (set_name, p_new_path, p_catalog_header^);
                pup$build_entry (p_directory_array^ [index].name, dummy_cycle_selector,
                      puc$valid_catalog_entry, entry);
                pup$check_if_item_excluded (entry, p_catalog_header^, item_excluded);
                IF item_excluded THEN
                  pup$display_excluded_item (entry, p_catalog_header^, status);
                ELSE
                  pfp$find_direct_info_record (^p_info_record^.body, p_directory_array^ [index].info_offset,
                        p_catalog_info, status);
                  IF status.normal THEN
                    pfp$find_permit_array (p_catalog_info, p_permit_array, status);
                    IF status.normal THEN
                      change_catalog_permits (p_new_path^, p_permit_array, old_permit_family,
                            new_permit_family, status);
                    IFEND;
                  IFEND;
                  pup$write_os_status (status, local_status);
                  change_catalog_content_permits (p_new_path^, old_permit_family, new_permit_family, status);
                  pup$write_os_status (status, local_status);
                  status.normal := TRUE;
                IFEND;
              ELSE
              CASEND;
            FOREND /change_catalogs/;
          IFEND;
        IFEND;
      IFEND;
      mmp$delete_scratch_segment (catalog_content_info, local_status);
    IFEND;
    pup$write_os_status (status, local_status);
  PROCEND change_catalog_content_permits;
?? TITLE := '  change_catalog_permits', EJECT ??

  PROCEDURE change_catalog_permits (path: pft$path;
        p_permit_array: pft$p_permit_array;
        old_permit_family: pft$name;
        new_permit_family: pft$name;
    VAR status: ost$status);

    VAR
      local_status: ost$status,
      new_permit_group: pft$group,
      p: pft$array_index;

    status.normal := TRUE;
    IF p_permit_array = NIL THEN
      RETURN;
    IFEND;

  /process_permit_list/
    FOR p := 1 TO UPPERBOUND (p_permit_array^) DO
      CASE p_permit_array^ [p].group.group_type OF
      = pfc$public =
        ;
      ELSE
        { This uses the variant record    'trick' since the family  is    always the first field
        {of all of the variants.
        IF p_permit_array^ [p].group.family_description.family = old_permit_family THEN
          new_permit_group := p_permit_array^ [p].group;
          new_permit_group.family_description.family := new_permit_family;
          display (' pfp$permit_catalog ');
          pfp$permit_catalog (path, new_permit_group, p_permit_array^ [p].usage_permissions, p_permit_array^
                [p].share_requirements, p_permit_array^ [p].application_info, status);
          IF status.normal THEN
            display (' pfp$delete_catalog_permit');
            pfp$delete_catalog_permit (path, p_permit_array^ [p].group, status);
            IF status.normal THEN
              total_catalog_permits_changed := total_catalog_permits_changed + 1;
            ELSE
              pup$display_line (' -- unable to delete old catalog permit ', local_status);
              pup$write_path (path, local_status);
              pup$write_os_status (status, local_status);
            IFEND;
          ELSE
            pup$display_line (' -- unable to create new catalog permit ', local_status);
            pup$write_path (path, local_status);
            pup$write_os_status (status, local_status);
          IFEND;
        IFEND;
      CASEND;
    FOREND /process_permit_list/;

  PROCEND change_catalog_permits;

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

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


{  pdt change_file_permits_pdt (
{  file,f:file=$required
{  family_name, fn: name = $required
{  new_family_name, nfn: name = $required
{  status)

?? PUSH (LISTEXT := ON) ??

    VAR
      change_file_permits_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table :=
        [^change_file_permits_pdt_names, ^change_file_permits_pdt_params];

    VAR
      change_file_permits_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 7] of
        clt$parameter_name_descriptor := [['FILE', 1], ['F', 1], ['FAMILY_NAME', 2], ['FN', 2], [
        'NEW_FAMILY_NAME', 3], ['NFN', 3], ['STATUS', 4]];

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

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

{ FAMILY_NAME FN }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ NEW_FAMILY_NAME NFN }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ 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,
      local_status: ost$status,
      new_permit_family: pft$name,
      old_permit_family: pft$name,
      p_path: ^pft$path,
      path_container: clt$path_container;

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

    pup$crack_permanent_file ('FILE', - $put$cycle_reference_selections [], path_container, p_path,
          cycle_selector_specified, cycle_selector, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    crack_family_names (old_permit_family, new_permit_family, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pup$display_line (' CHANGE_FILE_PERMITS', status);
    pup$write_path (p_path^, status);
    pup$display_line (old_permit_family, status);
    pup$display_line (new_permit_family, status);

    pup$initialize_summary_status;
    total_file_permits_changed := 0;
    total_catalog_permits_changed := 0;

    pup$change_file_permits (p_path^, old_permit_family, new_permit_family, status);

    display_change_permit_totals;
    pup$get_summary_status (status);
    pup$write_os_status (status, local_status);
  PROCEND pup$change_file_permits_command;

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

  PROCEDURE pup$change_file_permits (path: pft$path;
        old_permit_family: pft$name;
        new_permit_family: pft$name;
    VAR status: ost$status);

    VAR
      entry: put$entry,
      index: integer,
      file_info: amt$segment_pointer,
      group: pft$group,
      local_status: ost$status,
      p_catalog_header: ^put$catalog_header,
      p_directory: pft$p_directory_array,
      p_permit_array: pft$p_permit_array,
      p_info_record: pft$p_info_record,
      set_name: stt$set_name;


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

    PUSH p_catalog_header: [1 .. UPPERBOUND (path)];
    pup$build_catalog_header (set_name, ^path, p_catalog_header^);
    IF status.normal THEN
      mmp$create_scratch_segment (amc$sequence_pointer, mmc$as_random, file_info, status);
    IFEND;
    IF status.normal THEN
      RESET file_info.sequence_pointer;
      group.group_type := pfc$public;
      pfp$get_item_info (path, group, $pft$catalog_info_selections [], $pft$file_info_selections
            [pfc$file_directory, pfc$file_permits], file_info.sequence_pointer, status);
      IF status.normal THEN
        RESET file_info.sequence_pointer;
        pfp$find_next_info_record (file_info.sequence_pointer, p_info_record, status);
      IFEND;
      IF status.normal THEN
        pfp$find_directory_array (p_info_record, p_directory, status);
      IFEND;
      IF status.normal AND (p_directory = NIL) THEN
        osp$set_status_abnormal ('PU', pfe$unknown_permanent_file, path [UPPERBOUND (path)], status);
      IFEND;
      IF status.normal THEN
        pfp$find_direct_info_record (^p_info_record^.body, p_directory^ [1].info_offset, p_info_record,
              status);
      IFEND;
      IF status.normal THEN
        pfp$find_permit_array (p_info_record, p_permit_array, status);
      IFEND;
      IF status.normal THEN
        change_file_permits (path, p_permit_array, old_permit_family, new_permit_family, status);
      IFEND;
      mmp$delete_scratch_segment (file_info, local_status);
    IFEND;
  PROCEND pup$change_file_permits;
?? TITLE := '  change_file_permits', EJECT ??

  PROCEDURE change_file_permits (path: pft$path;
        p_permit_array: pft$p_permit_array;
        old_permit_family: pft$name;
        new_permit_family: pft$name;
    VAR status: ost$status);

    VAR
      local_status: ost$status,
      new_permit_group: pft$group,
      p: pft$array_index;

    status.normal := TRUE;
    IF p_permit_array = NIL THEN
      RETURN;
    IFEND;

  /process_file_permits/
    FOR p := 1 TO UPPERBOUND (p_permit_array^) DO
      CASE p_permit_array^ [p].group.group_type OF
      = pfc$public =
        ;
      ELSE
        { This uses the variant record    'trick' since the family  is    always the first field
        {of all of the variants.
        IF p_permit_array^ [p].group.family_description.family = old_permit_family THEN
          new_permit_group := p_permit_array^ [p].group;
          new_permit_group.family_description.family := new_permit_family;
          display (' pfp$permit ');
          pfp$permit (path, new_permit_group, p_permit_array^ [p].usage_permissions, p_permit_array^ [p].
                share_requirements, p_permit_array^ [p].application_info, status);
          IF status.normal THEN
            display (' pfp$delete_permit');
            pfp$delete_permit (path, p_permit_array^ [p].group, status);
            IF status.normal THEN
              total_file_permits_changed := total_file_permits_changed + 1;
            ELSE
              pup$display_line (' -- unable to delete old file permit ', local_status);
              pup$write_path (path, local_status);
              pup$write_os_status (status, local_status);
            IFEND;
          ELSE
            pup$display_line (' -- unable to create new file permit ', local_status);
            pup$write_path (path, local_status);
            pup$write_os_status (status, local_status);
          IFEND;
        IFEND;
      CASEND;
    FOREND /process_file_permits/;

  PROCEND change_file_permits;
?? TITLE := ' crack_family_names', EJECT ??

  PROCEDURE [INLINE] crack_family_names (VAR old_permit_family: pft$name;
    VAR new_permit_family: pft$name;
    VAR status: ost$status);

    VAR
      value: clt$value;

    clp$get_value ('FAMILY_NAME', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    old_permit_family := value.name.value;

    clp$get_value ('NEW_FAMILY_NAME', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    new_permit_family := value.name.value;

    IF old_permit_family = new_permit_family THEN
      osp$set_status_abnormal (puc$pf_utility_id, pue$new_name_must_be_different, 'NEW_FAMILY_NAME', status);
      osp$append_status_parameter (osc$status_parameter_delimiter, ' FAMILY_NAME', status);
    IFEND;

  PROCEND crack_family_names;

?? TITLE := '    display_change_permit_totals ', EJECT ??

  PROCEDURE display_change_permit_totals;

    VAR
      local_status: ost$status;

    pup$display_blank_lines (1, local_status);
    pup$display_line (' CHANGE SUMMARY: ', local_status);
    pup$display_integer ('   NUMBER OF CATALOG PERMITS CHANGED:', total_catalog_permits_changed,
          local_status);
    pup$display_integer ('   NUMBER OF FILE PERMITS CHANGED:', total_file_permits_changed, local_status);
  PROCEND display_change_permit_totals;


MODEND pum$change_all_permits;
