?? LEFT := 1, RIGHT := 110 ??
?? NEWTITLE := 'NAM/VE: Miscellaneous Routines (236) For Networks' ??
MODULE nam$miscellaneous_236;
{ PURPOSE:
{   The purpose of this module is to contain NAM/VE miscellaneous routines
{   that are gated only to ring 6.
{
?? PUSH (LISTEXT := ON) ??
?? NEWTITLE := '  Global Declarations', EJECT ??
*copyc nat$checksum
*copyc nat$network_address
*copyc nat$data_fragments
?? POP ??
?? TITLE := '  External Procedures', EJECT ??
*copyc mmp$create_segment
*copyc mmp$delete_segment
*copyc nap$system_id
*copyc pfp$find_directory_array
*copyc pfp$find_next_info_record
*copyc pfp$get_multi_item_info
?? TITLE := '[XDCL,#GATE] NAP$GET_CATALOG_FILE_COUNT', EJECT ??

  PROCEDURE [XDCL, #GATE] nap$get_catalog_file_count (path: pft$path;
    VAR files: 0 .. 7fffffff(16);
    VAR status: ost$status);

    VAR
      directory: pft$p_directory_array,
      group: pft$group,
      info: pft$p_info,
      info_record: pft$p_info_record,
      info_segment_pointer: mmt$segment_pointer,
      local_status: ost$status;

    status.normal := TRUE;
    mmp$create_segment (NIL, mmc$sequence_pointer, 1, info_segment_pointer, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    info := info_segment_pointer.seq_pointer;
    RESET info;

    group.group_type := pfc$member;
    group.member_description.family := osc$null_name;
    group.member_description.account := osc$null_name;
    group.member_description.project := osc$null_name;
    group.member_description.user := osc$null_name;

    files := 0;
    pfp$get_multi_item_info (path, group, $pft$catalog_info_selections [], $pft$file_info_selections
          [pfc$file_directory], info, status);
    IF status.normal THEN
      RESET info;
      pfp$find_next_info_record (info, info_record, status);
      IF status.normal THEN
        pfp$find_directory_array (info_record, directory, status);
        IF status.normal THEN
          IF directory = NIL THEN
            files := 0;
          ELSE
            files := UPPERBOUND (directory^);
          IFEND;
        IFEND;
      IFEND;
    IFEND;

    mmp$delete_segment (info_segment_pointer, 1, local_status);
    IF status.normal AND (NOT local_status.normal) THEN
      status := local_status;
    IFEND;
  PROCEND nap$get_catalog_file_count;
?? TITLE := '  [XDCL, #GATE] nap$local_system_id', EJECT ??

  FUNCTION [XDCL, #GATE] nap$local_system_id: nat$system_identifier;

      nap$local_system_id := nap$system_id ();
  FUNCEND nap$local_system_id;
?? TITLE := '  [XDCL, #GATE] nap$xns_checksum', EJECT ??

  FUNCTION [XDCL, #GATE] nap$xns_checksum (data_fragments: nat$data_fragments): nat$checksum_value;

*copyc nah$xns_checksum

    TYPE
      data_array = array [0 .. (nac$max_data_length - 3) DIV 2] of unsigned_sixteen_bit,
      odd_byte_record = record
        first_byte: unsigned_eight_bit,
        remaining_bytes: data_array,
      recend,
      unsigned_eight_bit = 0 .. 0ff(16),
      unsigned_sixteen_bit = 0 .. 0ffff(16);

    VAR
      accumulator: 0 .. 07fffffffffffffff(16),
      even_first_byte_data: ^data_array,
      fragment_index: integer,
      fragment_length: nat$data_length,
      fragment_address: ^cell,
      index: 0 .. nac$max_data_length DIV 2,
      max_index: - 1 .. nac$max_data_length DIV 2,
      mid_word: boolean,
      odd_first_byte_data: ^odd_byte_record,
      one_byte: ^unsigned_eight_bit;

    accumulator := 0;
    mid_word := FALSE;

    FOR fragment_index := 1 TO UPPERBOUND (data_fragments) DO
      fragment_address := data_fragments [fragment_index].address;
      fragment_length := data_fragments [fragment_index].length;
      IF (fragment_address <> NIL) AND (fragment_length > 0) THEN

{  Check for a fragment that starts in the middle of a 16 bit parcel.

        IF mid_word THEN
          odd_first_byte_data := fragment_address;
          accumulator := accumulator + (odd_first_byte_data^.first_byte * 2);
          accumulator := (accumulator MOD 65536) + (accumulator DIV 65536);
          fragment_length := fragment_length - 1;
          mid_word := FALSE;
          even_first_byte_data := ^odd_first_byte_data^.remaining_bytes;
        ELSE
          even_first_byte_data := fragment_address;
        IFEND;

        max_index := (fragment_length DIV 2) - 1;

{ Add in data 1 16 bit word at a time and shift around left 1 bit.

        FOR index := 0 TO max_index DO
          accumulator := (accumulator + even_first_byte_data^ [index]) * 2;
          accumulator := (accumulator MOD 65536) + (accumulator DIV 65536);
        FOREND;

{  Include the last 8 bit byte if there are an odd number of bytes.

        IF fragment_length MOD 2 = 1 THEN
          accumulator := (accumulator + ((even_first_byte_data^ [max_index + 1] DIV 256) * 256)) * 2;
          accumulator := (accumulator MOD 65536) + (accumulator DIV 65536);
          mid_word := TRUE;
        IFEND;
      IFEND;
    FOREND;

    accumulator := (accumulator MOD 65536) + (accumulator DIV 65536);

{  A value with all bits set (-0) represents "no checksum", and must be
{  converted to +0.

    IF accumulator = nac$no_checksum THEN
      nap$xns_checksum := 0;
    ELSE
      nap$xns_checksum := accumulator;
    IFEND;

  FUNCEND nap$xns_checksum;
MODEND nam$miscellaneous_236;

