?? RIGHT := 110 ??
?? NEWTITLE := 'DEFINE_SUBPRODUCT Utility: Module RAM$CREATE_ELEMENT_LIST.' ??
MODULE ram$create_element_list;

{ PURPOSE:
{   This module contains the procedures to write information
{   about each item in a catalog to an element_list.  Items in a catalog
{   can be validated for allowable ring attributes, file_permits,
{   and cycle numbers.
{
{ DESIGN:
{   Permanent file procedures are used to create a sequence containing
{   information about all the items of a catalog.  Only the information that
{   is needed for installation is moved to another sequence called
{   the element_list.
{   The compiled module resides in RAF$LIBRARY.
{
{ NOTES:
{
{


?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc rae$package_software_cc
*copyc pmt$condition
*copyc ost$status
*copyc rat$path
*copyc rat$subproduct_info_pointers
*copyc rat$subproduct_info_p
*copyc rat$subproduct_info_types
*copyc rat$validation_selections
?? POP ??
*copyc amp$fetch
*copyc amp$fetch_access_information
*copyc amp$get_segment_pointer
*copyc clp$convert_integer_to_rjstring
*copyc clp$convert_integer_to_string
*copyc clp$trimmed_string_size
*copyc fsp$close_file
*copyc mmp$create_segment
*copyc mmp$delete_segment
*copyc ocp$checksum
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc osp$set_status_abnormal
*copyc pfp$find_direct_info_record
*copyc pfp$find_directory_array
*copyc pfp$find_next_info_record
*copyc pfp$find_file_description
*copyc pfp$get_item_info
*copyc pfp$get_multi_item_info
*copyc osp$generate_error_message
*copyc rap$add_name_to_path_ref
*copyc rap$get_file_information
*copyc rap$test_cycles
*copyc rap$test_permits

?? TITLE := 'Global Declarations Declared by This Module', EJECT ??

  VAR
    subproduct_info_seq_p: ^rat$subproduct_info_sequence;

?? TITLE := '[XDCL] rap$create_element_list', EJECT ??


{ PURPOSE:
{   This procedure will create the element list for the PACS catalog.
{
{ DESIGN:
{   This procedure creates the permanent file sequence pointer, and calls
{   get_catalog_information to continue processing the element_list.
{   Then the subproduct_info_pointers are updated with their new values.
{
{ NOTES:
{
{

  PROCEDURE [XDCL] rap$create_element_list
    (    catalog_ref_p: ^fst$file_reference;
         catalog_path: pft$path;
         validation_selections: rat$validation_selections;
         checksum_contents: boolean;
     VAR validation_errors: {output} boolean;
     VAR subproduct_info_pointers: {input, output} rat$subproduct_info_pointers;
     VAR status: ost$status);


    VAR
      element: rat$element,
      local_status: ost$status,
      pf_info_seq_p: pft$p_info,
      pf_segment_pointer: mmt$segment_pointer,
      product_file_size: integer,
      subproduct_element_count: rat$subproduct_element_count,
      subproduct_size: integer;

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

{ PURPOSE:
{   This procedure cleans up when an abort situation occurs
{   within the block structure.
{
{ DESIGN:
{   If the segment has been created, it will be deleted before the
{   the procedure returns.
{
{ NOTES:
{
{
    PROCEDURE abort_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        ignore_status: ost$status;

      IF pf_segment_pointer.seq_pointer <> NIL THEN
        mmp$delete_segment (pf_segment_pointer, 1, ignore_status);
        pf_segment_pointer.seq_pointer := NIL;
      IFEND;

    PROCEND abort_handler;

?? OLDTITLE, EJECT ??


    status.normal := TRUE;
    product_file_size := 0;
    subproduct_element_count := 0;
    subproduct_size := 0;
    validation_errors := FALSE;

    subproduct_info_seq_p := subproduct_info_pointers.subproduct_info_seq_p;
    RESET subproduct_info_seq_p TO subproduct_info_pointers.element_list_p;

    pf_segment_pointer.kind := mmc$sequence_pointer;
    pf_segment_pointer.seq_pointer := NIL;

    mmp$create_segment (NIL, mmc$sequence_pointer, 1, pf_segment_pointer, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    osp$establish_block_exit_hndlr (^abort_handler);

  /main/
    BEGIN
      pf_info_seq_p := pf_segment_pointer.seq_pointer;
      RESET pf_info_seq_p;

      get_catalog_information (catalog_ref_p, catalog_path, pf_info_seq_p, validation_selections, TRUE,
            checksum_contents, validation_errors, element, product_file_size, subproduct_size,
            subproduct_element_count, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      subproduct_info_pointers.attributes_p^.product_file_size := product_file_size;
      subproduct_info_pointers.attributes_p^.user_permanent_file_size := 0;
      subproduct_info_pointers.attributes_p^.service_critical_file_size := 0;
      subproduct_info_pointers.attributes_p^.size := subproduct_size;
      subproduct_info_pointers.attributes_p^.first_level_element_count := element.element_count;
      { Subtract 1 from the subproduct element count so that the PACS catalog is not included.}
      subproduct_info_pointers.attributes_p^.subproduct_element_count := subproduct_element_count - 1;
      subproduct_info_pointers.subproduct_info_seq_p := subproduct_info_seq_p;

    END /main/;

    osp$disestablish_cond_handler;

    IF pf_segment_pointer.seq_pointer <> NIL THEN
      mmp$delete_segment (pf_segment_pointer, 1, local_status);
      pf_segment_pointer.seq_pointer := NIL;
      IF status.normal AND (NOT local_status.normal) THEN
        status := local_status;
      IFEND;
    IFEND;

  PROCEND rap$create_element_list;

?? TITLE := 'get_catalog_information', EJECT ??

{ PURPOSE:
{   This procedure gathers all the information about a catalog and puts
{   the information in the element list.
{
{ DESIGN:
{   This procedure gathers information about a catalog using
{   the permanent file procedures.  PFP$GET_ITEM_INFO only
{   returns information about the catalog.  This is used to check
{   the catalog permits.  PFP$GET_MULTI_ITEM_INFO returns information
{   about all the files and catalogs one level down from the input catalog.
{   The directory_p^ conatains an array of records.  Each record contains
{   the name of one element, its type (file or catalog) and the offset into
{   the permanent file sequence where more information about the element
{   can be found.
{
{ NOTES:
{   This procedure is the only place where the subproduct sequence
{   is NEXTed and updated with information from the file and catalog elements.
{   Before each pfp call, pf_info_item_seq_p is set to the beginning of
{   information about the catalog being referenced at this level.
{   The subproduct size is a close estimation of the size of the
{   backup file of this catalog.

  PROCEDURE get_catalog_information
    (    catalog_ref_p: ^fst$file_reference;
         catalog_path: pft$path;
         pf_info_seq_p: pft$p_info;
         validation_selections: rat$validation_selections;
         first_call: boolean;
         checksum_contents: boolean;
     VAR validation_errors: boolean;
     VAR element: rat$element;
     VAR product_file_size {input} : integer;
     VAR subproduct_size {input} : integer;
     VAR subproduct_element_count {input} : rat$subproduct_element_count;
     VAR status: ost$status);


    VAR
      current_product_file_size: integer,
      current_subproduct_size: integer,
      directory_p: pft$p_directory_array,
      element_p: ^rat$element,
      element_returned: rat$element,
      file_path: rat$path,
      group: pft$group,
      i: pft$array_index,
      info_record_p: pft$p_info_record,
      local_status: ost$status,
      old_element_p: ^rat$element,
      path_p: ^pft$path,
      pf_info_item_seq_p: pft$p_info;


    status.normal := TRUE;
    group.group_type := pfc$public;

    element.name := catalog_path [UPPERBOUND (catalog_path)];
    element.permit.defined := FALSE;
    element.permit.permit_selections := $pft$permit_selections [];
    element.permit.share_requirements := $pft$share_requirements [];
    element.permit.application_info := '';
    element.active_element := TRUE;
    element.next_element_across_p := NIL;
    element.element_type := rac$catalog;
    element.element_count := 0;
    element.first_element_down_p := NIL;
    current_product_file_size := product_file_size;
    subproduct_element_count := subproduct_element_count + 1;

    pf_info_item_seq_p := pf_info_seq_p;

    pfp$get_item_info (catalog_path, group, $pft$catalog_info_selections
          [pfc$catalog_directory, pfc$catalog_permits, pfc$indirect_catalog_permits],
          $pft$file_info_selections [], pf_info_item_seq_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pf_info_item_seq_p := pf_info_seq_p;
    pfp$find_next_info_record (pf_info_item_seq_p, info_record_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pfp$find_directory_array (info_record_p, directory_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    rap$test_permits (validation_selections, catalog_ref_p, info_record_p, directory_p^ [1].info_offset,
          validation_errors, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pf_info_item_seq_p := pf_info_seq_p;
    pfp$get_multi_item_info (catalog_path, group, $pft$catalog_info_selections
          [pfc$catalog_directory, pfc$catalog_permits, pfc$indirect_catalog_permits],
          $pft$file_info_selections [pfc$file_directory, pfc$file_permits, pfc$file_description,
          pfc$file_cycles, pfc$cycle_label_descriptor], pf_info_item_seq_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pf_info_item_seq_p := pf_info_seq_p;
    pfp$find_next_info_record (pf_info_item_seq_p, info_record_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    current_subproduct_size := subproduct_size + ((info_record_p^.body_size *
            ((UPPERBOUND (catalog_path) DIV 2) * UPPERBOUND (catalog_path) + 91)) DIV 10);

    pfp$find_directory_array (info_record_p, directory_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF directory_p = NIL THEN  {EMPTY CATALOG}
      RETURN;
    IFEND;
    element.element_count := UPPERBOUND (directory_p^);

    PUSH path_p: [1 .. UPPERBOUND (catalog_path) + 1];
    FOR i := 1 TO UPPERBOUND (catalog_path) DO
      path_p^ [i] := catalog_path [i];
    FOREND;


    FOR i := 1 TO UPPERBOUND (directory_p^) DO
      path_p^ [UPPERBOUND (path_p^)] := directory_p^ [i].name;

      STRINGREP (file_path.path, file_path.size, catalog_ref_p^, '.', directory_p^ [i].name (1,
            clp$trimmed_string_size (directory_p^ [i].name)));

      NEXT element_p IN subproduct_info_seq_p;
      IF element_p = NIL THEN
        osp$set_status_abnormal ('RA', rae$accessed_beyond_memory_seg, '', status);
        RETURN;
      IFEND;

      IF (i = 1) AND (NOT first_call) THEN
        element.first_element_down_p := #REL (element_p, subproduct_info_seq_p^);
      IFEND;

      IF directory_p^ [i].name_type = pfc$file_name THEN

        rap$get_file_information (^file_path.path (1, file_path.size), path_p^, info_record_p,
              directory_p^ [i].info_offset, validation_selections, checksum_contents, validation_errors,
              element_returned, status);

        current_product_file_size := current_product_file_size + element_returned.size;
        current_subproduct_size := current_subproduct_size + element_returned.size;
        subproduct_element_count := subproduct_element_count + 1;

      ELSE {pfc$catalog_name}

        get_catalog_information (^file_path.path (1, file_path.size), path_p^, pf_info_item_seq_p,
              validation_selections, FALSE {SIF present}, checksum_contents, validation_errors,
              element_returned, current_product_file_size, current_subproduct_size,
              subproduct_element_count, status);

      IFEND;
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      element_p^ := element_returned;

      IF i > 1 THEN
        old_element_p^.next_element_across_p := #REL (element_p, subproduct_info_seq_p^);
      IFEND;

      old_element_p := element_p;

    FOREND;

    product_file_size := current_product_file_size;
    subproduct_size := current_subproduct_size;

  PROCEND get_catalog_information;

MODEND ram$create_element_list;





