?? RIGHT := 110 ??
?? TITLE := 'Display_Binary_Log - Display NOS/VE Binary Log' ??
?? NEWTITLE := '   ' ??
MODULE lgm$display_binary_log;

  CONST
    maximum_integer = 7fffffffffff(16);

?? PUSH (LISTEXT := ON) ??
*copyc cle$ecc_expression_result
*copyc pme$logging_exceptions
*copyc ost$string
*copyc jmt$system_supplied_name
*copyc sfd$type_declarations
*copyc sft$statistic_buffer
*copyc pmp$get_unique_name
*copyc pmp$get_compact_date_time
*copyc pmp$format_compact_date
*copyc pmp$format_compact_time
*copyc pmp$this_is_a_leap_year
*copyc sft$global_log_statistic_header
*copyc pmp$exit
*copyc amp$file
*copyc amp$rewind
*copyc amp$get_segment_pointer
*copyc amp$open
*copyc amp$close
*copyc amp$get_next
*copyc amp$put_next
*copyc pmd$system_log_interface
*copyc pmp$cause_condition
*copyc pmp$establish_condition_handler
*copyc osp$set_status_abnormal
*copyc osp$append_status_integer
*copyc osp$append_status_parameter
*copyc osp$status_condition_code
*copyc osp$unpack_status_condition
*copyc clp$scan_token
*copyc clp$convert_string_to_integer
*copyc clp$convert_value_to_string
*copyc clp$push_utility
*copyc clp$pop_utility
*copyc clp$scan_command_file
*copyc clp$end_scan_command_file
*copyc clp$scan_parameter_list
*copyc clp$convert_integer_to_rjstring
*copyc clp$convert_integer_to_string
*copyc clp$get_value
*copyc clp$test_parameter
*copyc clt$integer
*copyc clp$get_set_count
*copyc clp$get_path_description
*copyc clp$test_range
*copyc lgp$parse_statistic
*copyc pfp$define
*copyc pfp$define_catalog
?? POP ??
?? EJECT, TITLE := 'Global definitions' ??

  VAR
    input_buffer: sft$statistic_buffer,
    input_file_position: amt$file_position,
    p_stat_header: ^sft$global_log_statistic_header,
    p_stat_counters: sft$counters,
    p_stat_descript: ^sft$descriptive_data,
    abnormal_status: ost$status,
    input_file,
    output_file,
    command_file: amt$file_identifier,
    abnormal_condition: pmt$condition := [pmc$user_defined_condition, abnormal_status_condition],
    local_status: ost$status,
    input_file_name: amt$local_file_name,
    output_file_name: amt$local_file_name,
    group_file_name: amt$local_file_name,
    group_file_path: array [1 .. 3] of pft$name := [osc$null_name, osc$null_name, osc$null_name],
    file_byte_address: amt$file_byte_address;

  VAR
    log_type: pmt$global_binary_logs,
    input_from_file: boolean; { true if not reading from active log }

  VAR
    alpha_chars: [STATIC] set of char := ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
      'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];

?? EJECT ??
{  Definitions for data analysis code  }

  CONST
    max_name_size = 32,
    blank_name = '                                ',
    blank_passw = '                               ',
    abnormal_status_condition = 'ABNORMAL_STATUS                ',
    default_output = '$OUTPUT                        ';

  TYPE
    name_type = string (max_name_size),

    task_succ_group_list = array [ * ] of ^group_ctl_blk,

    job_succ_group_list = array [ * ] of ^group_ctl_blk,

    metric_list = array [ * ] of ^metric_ctl_blk;

  TYPE
    pred_job_blk = record
      job_seq_number: jmt$system_supplied_name,
      pred_job_link: ^pred_job_blk,
    recend;

  TYPE
    pred_task_blk = record
      global_task_id: ost$global_task_id,
      pred_task_link: ^pred_task_blk,
    recend;

  TYPE
    stat_code_ctl_blk = record
      code_chain_link: ^stat_code_ctl_blk,
      stat_code: sft$statistic_code,
    recend;

  TYPE
    group_ctl_blk = record
      name: name_type,
      pred_task_group_name: name_type,
      pred_job_group_name: name_type,
      group_chain_link: ^group_ctl_blk,
      stat_specified: boolean,
      stat_code: sft$statistic_code,
      date_specified: boolean,
      time_specified: boolean,
      start_dt: ost$date_time,
      end_dt: ost$date_time,
      p_task_succ_group_list: ^task_succ_group_list,
      p_job_succ_group_list: ^job_succ_group_list,
      desc_specified: boolean,
      desc_data_size: 0 .. sfc$max_descriptive_data_size,
      desc_data: string (sfc$max_descriptive_data_size),
      between_active: boolean,
      p_metric_list: ^metric_list,
      copy_requested: boolean,
      copy_file_identifier: amt$file_identifier,
      p_pred_task_head: ^pred_task_blk,
      p_pred_job_head: ^pred_job_blk,
      desc_needed: boolean,
      p_desc_blk: ^desc_blk,
    recend;

  TYPE
    metric_ctl_blk = record
      name: name_type,
      group_name: name_type,
      metric_chain_link: ^metric_ctl_blk,
      p_group_ctl_blk: ^group_ctl_blk,
      element_sequence: amt$segment_pointer,
      element_count: integer,
      incremental: boolean,
      previous_value: integer,
      first_element: boolean,
      maximum: integer,
      minimum: integer,
      time_stamp_needed: boolean,
      p_report_ctl_blk: ^report_ctl_blk,
      file_identifier: amt$file_identifier,
      scale_factor: integer,
      unit: string (max_name_size),

      case metric_type: metric_types of
      = counter_metric =
        counter_number: 1 .. sfc$max_number_of_counters,
      casend,
    recend;

  TYPE
    metric_types = (counter_metric, interval_metric, expression_metric, undefined_metric);

  TYPE
    date_time_metric = record
      counter_value: integer,
      time_value: integer,
      date_value: integer,
    recend;

  TYPE
    input_log_blk = record
      log_chain_link: ^input_log_blk,
      log_file_name: amt$local_file_name,
      file_ref: clt$file_reference,
      start_time: ost$date_time,
      end_time: ost$date_time,
    recend;

  TYPE
    desc_blk = record
      desc_chain_link: ^desc_blk,
      count: integer,
      desc_data_size: 0 .. sfc$max_descriptive_data_size,
      desc_data: string (sfc$max_descriptive_data_size),
    recend;

?? EJECT ??

  TYPE
    report_ctl_blk = record
      report_chain_link: ^report_ctl_blk,
      title: ost$string,
      metric_name: name_type,
      p_metric_ctl_blk: ^metric_ctl_blk,
      case report_type: report_types of
      = summary_report =
        low_limit: integer,
        high_limit: integer,
        num: boolean,
        mean: boolean,
        min: boolean,
        max: boolean,
        variance: boolean,
        interval: boolean,
        sum: boolean,
        interval_value: integer,

      = distribution_report =
        x_low_limit,
        x_high_limit: integer,
        cnt_low_limit,
        cnt_high_limit: integer,
        display_option: display_types,
        x_interval: interval_types,

      = datades_report, dump_report, gen_group_file =
        group_name: name_type,
        p_group_ctl_blk: ^group_ctl_blk,
        counter_radix: array [1 .. sfc$max_number_of_counters] of 1 .. 16,
        file_name: amt$local_file_name,
        permanent: boolean,

      = time_distribution_report =
        metric_low_limit: 0 .. 0ffffffff(16),
        metric_high_limit: 0 .. 0ffffffff(16),

      casend,
    recend,

    report_types = (list_report, summary_report, distribution_report, datades_report, scatter_report,
      dump_report, gen_group_file, time_distribution_report),
    display_types = (max_min_bound, first_max_centered, second_max_centered),
    interval_types = (self_adjust, large, medium, small);

?? EJECT ??
{  Data structure variables  }

  VAR
    stat_name_chain_head: ^stat_code_ctl_blk,
    log_chain_head: ^input_log_blk,
    group_chain_head: ^group_ctl_blk,
    metric_chain_head: ^metric_ctl_blk,
    report_chain_head: ^report_ctl_blk,
    p_log_blk: ^input_log_blk;

  VAR
    p_access_array: ^array [ * ] of amt$access_selection,

    read_only_access_array: [STATIC, READ] array [1 .. 1] of amt$access_selection := [[amc$access_mode,
      $pft$usage_selections [pfc$read]]];

?? TITLE := 'DISBL Command Utility Processor', NEWTITLE := '  ' ??
?? EJECT, TITLE := 'Program header' ??

  PROGRAM lgp$display_binary_log (program_parameters: clt$parameter_list;
    VAR program_status: ost$status);

?? EJECT, TITLE := 'Local Variables' ??
?? RIGHT := 110 ??
{ PDT command_pdt (
{     input, i:  FILE
{     type, t:  KEY statistic, statistics, account,accounting,...
{       engineering = statistic
{     output, o: FILE = $OUTPUT
{     status )

?? PUSH (LISTEXT := ON) ??

    VAR
      command_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^command_pdt_names,
        ^command_pdt_params];

    VAR
      command_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 7] of
        clt$parameter_name_descriptor := [['INPUT', 1], ['I', 1], ['TYPE', 2], ['T', 2], ['OUTPUT', 3], ['O',
        3], ['STATUS', 4]];

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

{ INPUT I }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$file_value]],

{ TYPE T }
      [[clc$optional_with_default, ^command_pdt_dv2], 1, 1, 1, 1, clc$value_range_not_allowed,
        [^command_pdt_kv2, clc$keyword_value]],

{ OUTPUT O }
      [[clc$optional_with_default, ^command_pdt_dv3], 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]]];

    VAR
      command_pdt_kv2: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 5] of ost$name := ['STATISTIC',
        'STATISTICS', 'ACCOUNT', 'ACCOUNTING', 'ENGINEERING'];

    VAR
      command_pdt_dv2: [STATIC, READ, cls$pdt_names_and_defaults] string (9) := 'statistic';

    VAR
      command_pdt_dv3: [STATIC, READ, cls$pdt_names_and_defaults] string (7) := '$OUTPUT';

?? POP ??
?? EJECT ??
{  The subcommand list  }

{ table sub_command_list t=c s=local
{ command (define_group                     ,defg) defg_subcommand cm=local
{ command (define_metric                    ,defm) defm_subcommand cm=local
{ command (display_summary                  ,diss) diss_subcommand cm=local
{ command (display_distribution             ,disd) disd_subcommand cm=local
{ command (display_logged_statistics        ,disls) disls_subcommand cm=local
{ command (display_time_distribution        ,distd) distd_subcommand cm=local
{ command (display_descriptive_data         ,disdd) disdd_subcommand cm=local
{ command (dump_group                       ,dumg) dumg_subcommand cm=local
{ command (generate_group_file              ,gengf) gengf_subcommand cm=local
{ command (quit                             ,qui) qui_subcommand cm=local
{ tablend

?? PUSH (LISTEXT := ON) ??
VAR
  sub_command_list: [STATIC, READ] ^clt$command_table := ^sub_command_list_entries,

  sub_command_list_entries: [STATIC, READ] array [1 .. 20] of  clt$command_table_entry := [
  {} ['DEFG                           ', clc$abbreviation_entry, clc$advertised_entry, 1,
        clc$automatically_log, clc$linked_call, ^defg_subcommand],
  {} ['DEFINE_GROUP                   ', clc$nominal_entry, clc$advertised_entry, 1,
        clc$automatically_log, clc$linked_call, ^defg_subcommand],
  {} ['DEFINE_METRIC                  ', clc$nominal_entry, clc$advertised_entry, 2,
        clc$automatically_log, clc$linked_call, ^defm_subcommand],
  {} ['DEFM                           ', clc$abbreviation_entry, clc$advertised_entry, 2,
        clc$automatically_log, clc$linked_call, ^defm_subcommand],
  {} ['DISD                           ', clc$abbreviation_entry, clc$advertised_entry, 4,
        clc$automatically_log, clc$linked_call, ^disd_subcommand],
  {} ['DISDD                          ', clc$abbreviation_entry, clc$advertised_entry, 7,
        clc$automatically_log, clc$linked_call, ^disdd_subcommand],
  {} ['DISLS                          ', clc$abbreviation_entry, clc$advertised_entry, 5,
        clc$automatically_log, clc$linked_call, ^disls_subcommand],
  {} ['DISPLAY_DESCRIPTIVE_DATA       ', clc$nominal_entry, clc$advertised_entry, 7,
        clc$automatically_log, clc$linked_call, ^disdd_subcommand],
  {} ['DISPLAY_DISTRIBUTION           ', clc$nominal_entry, clc$advertised_entry, 4,
        clc$automatically_log, clc$linked_call, ^disd_subcommand],
  {} ['DISPLAY_LOGGED_STATISTICS      ', clc$nominal_entry, clc$advertised_entry, 5,
        clc$automatically_log, clc$linked_call, ^disls_subcommand],
  {} ['DISPLAY_SUMMARY                ', clc$nominal_entry, clc$advertised_entry, 3,
        clc$automatically_log, clc$linked_call, ^diss_subcommand],
  {} ['DISPLAY_TIME_DISTRIBUTION      ', clc$nominal_entry, clc$advertised_entry, 6,
        clc$automatically_log, clc$linked_call, ^distd_subcommand],
  {} ['DISS                           ', clc$abbreviation_entry, clc$advertised_entry, 3,
        clc$automatically_log, clc$linked_call, ^diss_subcommand],
  {} ['DISTD                          ', clc$abbreviation_entry, clc$advertised_entry, 6,
        clc$automatically_log, clc$linked_call, ^distd_subcommand],
  {} ['DUMG                           ', clc$abbreviation_entry, clc$advertised_entry, 8,
        clc$automatically_log, clc$linked_call, ^dumg_subcommand],
  {} ['DUMP_GROUP                     ', clc$nominal_entry, clc$advertised_entry, 8,
        clc$automatically_log, clc$linked_call, ^dumg_subcommand],
  {} ['GENERATE_GROUP_FILE            ', clc$nominal_entry, clc$advertised_entry, 9,
        clc$automatically_log, clc$linked_call, ^gengf_subcommand],
  {} ['GENGF                          ', clc$abbreviation_entry, clc$advertised_entry, 9,
        clc$automatically_log, clc$linked_call, ^gengf_subcommand],
  {} ['QUI                            ', clc$abbreviation_entry, clc$advertised_entry, 10,
        clc$automatically_log, clc$linked_call, ^qui_subcommand],
  {} ['QUIT                           ', clc$nominal_entry, clc$advertised_entry, 10,
        clc$automatically_log, clc$linked_call, ^qui_subcommand]];

?? POP ??


?? EJECT, TITLE := 'PROCEDURE initialize' ??

    PROCEDURE initialize;

      TYPE
        log_keywords = (account, accounting, statistic, statistics, engineering),
        keyword_set = set of log_keywords;

      VAR
        keyword_index: log_keywords,
        keyword_array: [STATIC, READ] array [log_keywords] of string (16) := ['ACCOUNT         ',
          'ACCOUNTING      ', 'STATISTIC       ', 'STATISTICS      ', 'ENGINEERING     '],

        log_name_array: [STATIC, READ] array [pmt$global_binary_logs] of amt$local_file_name := [
          '$ACCOUNT_LOG                   ', '$ENGINEERING_LOG               ',
          '$HISTORY_LOG                   ', '$SECURITY                      ',
          '$STATISTIC_LOG                 '];

      VAR
        parameter_value: clt$value;

      VAR
        output_access_array: [STATIC, READ] array [1 .. 1] of amt$access_selection := [[amc$file_contents,
          amc$list]];

      VAR
        set_count: 0 .. clc$max_value_sets,
        temp_index: integer,
        act_file: clt$file,
        path: ^pft$path,
        path_con: clt$path_container,
        cycle_sel: clt$cycle_selector,
        open_pos: clt$open_position,
        p_log_blk: ^input_log_blk,
        log_chain_tail: ^input_log_blk;


      stat_name_chain_head := NIL;
      log_chain_head := NIL;
      group_chain_head := NIL;
      metric_chain_head := NIL;
      report_chain_head := NIL;

      { Process the command parameters }

      clp$scan_parameter_list (program_parameters, command_pdt, local_status);
      check_status (local_status);

      { Process the INPUT parameter }

      clp$test_parameter ('INPUT', input_from_file, local_status);
      check_status (local_status);

      IF input_from_file THEN
        clp$get_set_count ('INPUT', set_count, local_status);
        check_status (local_status);
        IF set_count > 0 THEN
          FOR temp_index := 1 TO set_count DO
            clp$get_value ('INPUT', temp_index, 1, clc$low, parameter_value, local_status);
            check_status (local_status);
            ALLOCATE p_log_blk;
            p_log_blk^.log_file_name := parameter_value.file.local_file_name;
            clp$get_path_description (parameter_value.file, p_log_blk^.file_ref, path_con, path, cycle_sel,
                  open_pos, local_status);
            check_status (local_status);
            p_log_blk^.log_chain_link := NIL;
            IF log_chain_head = NIL THEN
              log_chain_head := p_log_blk;
            ELSE
              log_chain_tail^.log_chain_link := p_log_blk;
            IFEND;
            log_chain_tail := p_log_blk;
          FOREND;
        IFEND;
        p_access_array := ^read_only_access_array;
      IFEND;

      { Process the OUTPUT parameter }

      clp$get_value ('OUTPUT', 1, 1, clc$low, parameter_value, local_status);
      check_status (local_status);
      output_file_name := parameter_value.file.local_file_name;

      { Process the TYPE parameter }

      clp$get_value ('TYPE', 1, 1, clc$low, parameter_value, local_status);
      check_status (local_status);

    /identify_log/
      FOR keyword_index := account TO engineering DO
        IF keyword_array [keyword_index] (1, parameter_value.name.size) = parameter_value.name.value (1,
              parameter_value.name.size) THEN
          EXIT /identify_log/
        IFEND;
      FOREND /identify_log/;

      IF keyword_index IN $keyword_set [statistic, statistics] THEN
        log_type := pmc$statistic_log;
      IFEND;

      IF keyword_index IN $keyword_set [account, accounting] THEN
        log_type := pmc$account_log;
      IFEND;

      IF keyword_index IN $keyword_set [engineering] THEN
        log_type := pmc$engineering_log;
      IFEND;

      IF NOT input_from_file THEN
        ALLOCATE p_log_blk;
        p_log_blk^.log_file_name := log_name_array [log_type];
        act_file.local_file_name := log_name_array [log_type];
        clp$get_path_description (act_file, p_log_blk^.file_ref, path_con, path, cycle_sel, open_pos,
              local_status);
        check_status (local_status);
        p_log_blk^.log_chain_link := NIL;
        log_chain_head := p_log_blk;
        p_access_array := ^read_only_access_array;
      IFEND;


      { Input files will be opened in the main program before Proc scan_log }

      { Open the output file }

      amp$open (output_file_name, amc$record, ^output_access_array, output_file, local_status);
      check_status (local_status);

    PROCEND initialize;
?? EJECT, TITLE := 'FUNCTION in_group' ??

    FUNCTION in_group (p_group_ctl_blk: ^group_ctl_blk;
          p_header: ^sft$global_log_statistic_header;
          p_counters: sft$counters;
          p_descript: ^sft$descriptive_data): boolean;

      VAR
        stat_rec_dt,
        dt_lower_bound,
        dt_upper_bound: integer;

      in_group := FALSE;

      { check stat_id and stat_code }

      IF p_group_ctl_blk^.stat_specified AND (p_header^.statistic_code <> p_group_ctl_blk^.stat_code) THEN
        RETURN;
      IFEND;

      { check descriptive data }

      IF p_group_ctl_blk^.desc_specified AND ((p_header^.descriptive_data_size = 0) OR (p_group_ctl_blk^.
            desc_data (1, p_group_ctl_blk^.desc_data_size) <> p_descript^ (1, p_group_ctl_blk^.
            desc_data_size))) THEN
        RETURN;
      IFEND;

      { check the date range }

      IF p_group_ctl_blk^.date_specified THEN
        stat_rec_dt := p_header^.date_time.year * 10000 + p_header^.date_time.month * 100 + p_header^.
              date_time.day;
        dt_lower_bound := p_group_ctl_blk^.start_dt.year * 10000 + p_group_ctl_blk^.start_dt.month * 100 +
              p_group_ctl_blk^.start_dt.day;
        dt_upper_bound := p_group_ctl_blk^.end_dt.year * 10000 + p_group_ctl_blk^.end_dt.month * 100 +
              p_group_ctl_blk^.end_dt.day;
        IF (stat_rec_dt < dt_lower_bound) OR (stat_rec_dt > dt_upper_bound) THEN
          RETURN;
        IFEND;
      IFEND;

      { check the time range }

      IF p_group_ctl_blk^.time_specified THEN
        stat_rec_dt := p_header^.date_time.hour * 10000 + p_header^.date_time.minute * 100 + p_header^.
              date_time.second;
        dt_lower_bound := p_group_ctl_blk^.start_dt.hour * 10000 + p_group_ctl_blk^.start_dt.minute * 100 +
              p_group_ctl_blk^.start_dt.second;
        dt_upper_bound := p_group_ctl_blk^.end_dt.hour * 10000 + p_group_ctl_blk^.end_dt.minute * 100 +
              p_group_ctl_blk^.end_dt.second;
        IF (stat_rec_dt < dt_lower_bound) OR (stat_rec_dt > dt_upper_bound) THEN
          RETURN;
        IFEND;
      IFEND;

      in_group := TRUE;

    FUNCEND in_group;
?? EJECT, TITLE := 'PROCEDURE print_title' ??

    PROCEDURE print_title (ctl_blk: report_ctl_blk;
          report_title: string ( * ));

      VAR
        center: integer,
        dt_str1,
        dt_str2: string (20),
        from_dt,
        to_dt: ost$date_time,
        g_ctl_blk: group_ctl_blk,
        line_image: string (132);

      VAR
        dashes: [STATIC, READ] string (75) :=
          '---------------------------------------------------------------------------';

      line_image (1) := '1';
      line_image (2, * ) := ctl_blk.title.value (1, 131);
      print (line_image);

      line_image := ' Display_Binary_Log       ';
      print (line_image);

      IF (ctl_blk.report_type = datades_report) OR (ctl_blk.report_type = dump_report) THEN
          g_ctl_blk := ctl_blk.p_group_ctl_blk^;
      ELSE
          g_ctl_blk := ctl_blk.p_metric_ctl_blk^.p_group_ctl_blk^;
      IFEND;

      IF (g_ctl_blk.date_specified) OR (g_ctl_blk.time_specified) THEN
        convert_date_time (g_ctl_blk.start_dt, dt_str1);
        convert_date_time (g_ctl_blk.end_dt, dt_str2);
      IFEND;
      IF (g_ctl_blk.date_specified) AND (g_ctl_blk.time_specified) THEN
        line_image := ' DATE : ';
        line_image (32, 7) := 'TIME : ';
        line_image (17, 2) := '..';
        line_image (47, 2) := '..';
        line_image (9, 8) := dt_str1 (1, 8);
        line_image (19, 8) := dt_str2 (1, 8);
        line_image (39, 8) := dt_str1 (11, 8);
        line_image (49, 8) := dt_str2 (11, 8);
      ELSE
        IF g_ctl_blk.date_specified THEN
          line_image := ' DATE : ';
          line_image (17, 2) := '..';
          line_image (9, 8) := dt_str1 (1, 8);
          line_image (19, 8) := dt_str2 (1, 8);
        ELSE
          IF g_ctl_blk.time_specified THEN
            line_image := ' TIME : ';
            line_image (17, 2) := '..';
            line_image (9, 8) := dt_str1 (11, 8);
            line_image (19, 8) := dt_str2 (11, 8);
          IFEND;
        IFEND;
      IFEND;
      IF (g_ctl_blk.date_specified) OR (g_ctl_blk.time_specified) THEN
        print (line_image);
      IFEND;

      line_image := '-';
      print (line_image);

      IF (ctl_blk.report_type = distribution_report) OR (ctl_blk.report_type = datades_report) THEN
        center := 60;
      ELSE
        center := 40;
      IFEND;

      line_image (center - (#SIZE (report_title) DIV 2), * ) := report_title;
      print (line_image);

      line_image (center - (#SIZE (report_title) DIV 2), * ) := dashes (1, #SIZE (report_title));
      line_image (1) := ' ';
      print (line_image);


      print ('-');

    PROCEND print_title;
?? EJECT, TITLE := 'PROCEDURE display_log_info' ??

    PROCEDURE display_log_info;

      VAR
        line_image: string (132);

      p_log_blk := log_chain_head;

      WHILE p_log_blk <> NIL DO
        line_image := '0   *****  LOG   SCANNED:';
        line_image (30, p_log_blk^.file_ref.path_name_size) := p_log_blk^.file_ref.path_name (1, p_log_blk^.
              file_ref.path_name_size);
        print (line_image);
        line_image := '           STARTING TIME:';
        convert_date_time (p_log_blk^.start_time, line_image (30, 20));
        print (line_image);
        line_image := '           ENDING   TIME:';
        convert_date_time (p_log_blk^.end_time, line_image (30, 20));
        print (line_image);
        p_log_blk := p_log_blk^.log_chain_link;
      WHILEND;

    PROCEND display_log_info;
?? EJECT, TITLE := 'PROCEDURE link_blocks' ??

    PROCEDURE link_blocks;

      VAR
        p_group_ctl_blk: ^group_ctl_blk,
        p_group_blk_temp: ^group_ctl_blk,
        task_succ_index,
        job_succ_index: integer,
        p_task_succ_group_list: ^task_succ_group_list,
        p_job_succ_group_list: ^job_succ_group_list,
        temp_index: integer,
        p_metric_ctl_blk: ^metric_ctl_blk,
        p_metric_list: ^metric_list,
        p_report_ctl_blk: ^report_ctl_blk,
        file_name: ost$name,
        metric_list_index: integer,
        temp_p_desc_blk: ^desc_blk;

      VAR
        file_access_selections: [STATIC, READ] array [1 .. 1] of amt$access_selection := [[amc$return_option,
          amc$return_at_close]];

      { Loop through the group chain... }

      p_group_ctl_blk := group_chain_head;
      WHILE p_group_ctl_blk <> NIL DO
        { First, chain the predecessor and successors by pointer to
        { successor group lists ( task and job ) }

        p_group_blk_temp := group_chain_head;
        task_succ_index := 0;
        job_succ_index := 0;
        WHILE p_group_blk_temp <> NIL DO
          IF p_group_blk_temp^.pred_task_group_name = p_group_ctl_blk^.name THEN
            task_succ_index := task_succ_index + 1;
          IFEND;
          IF p_group_blk_temp^.pred_job_group_name = p_group_ctl_blk^.name THEN
            job_succ_index := job_succ_index + 1;
          IFEND;
          p_group_blk_temp := p_group_blk_temp^.group_chain_link;
        WHILEND;

        IF task_succ_index > 0 THEN
          ALLOCATE p_task_succ_group_list: [1 .. task_succ_index];
          FOR temp_index := 1 TO task_succ_index DO
            p_task_succ_group_list^ [temp_index] := NIL;
          FOREND;
          p_group_ctl_blk^.p_task_succ_group_list := p_task_succ_group_list;
        IFEND;
        IF job_succ_index > 0 THEN
          ALLOCATE p_job_succ_group_list: [1 .. job_succ_index];
          FOR temp_index := 1 TO job_succ_index DO
            p_job_succ_group_list^ [temp_index] := NIL;
          FOREND;
          p_group_ctl_blk^.p_job_succ_group_list := p_job_succ_group_list;
        IFEND;

        IF (task_succ_index > 0) OR (job_succ_index > 0) THEN
          p_group_blk_temp := group_chain_head;
          task_succ_index := 1;
          job_succ_index := 1;
          WHILE p_group_blk_temp <> NIL DO
            IF p_group_blk_temp^.pred_task_group_name = p_group_ctl_blk^.name THEN
              p_group_ctl_blk^.p_task_succ_group_list^ [task_succ_index] := p_group_blk_temp;
              task_succ_index := task_succ_index + 1;
            IFEND;
            IF p_group_blk_temp^.pred_job_group_name = p_group_ctl_blk^.name THEN
              p_group_ctl_blk^.p_job_succ_group_list^ [job_succ_index] := p_group_blk_temp;
              job_succ_index := job_succ_index + 1;
            IFEND;
            p_group_blk_temp := p_group_blk_temp^.group_chain_link;
          WHILEND;
        IFEND;

        { Second, count the number of metrics that specify the current
        { group. }

        metric_list_index := 0;
        p_metric_ctl_blk := metric_chain_head;
        WHILE p_metric_ctl_blk <> NIL DO
          IF p_metric_ctl_blk^.group_name = p_group_ctl_blk^.name THEN
            metric_list_index := metric_list_index + 1;
            p_metric_ctl_blk^.p_group_ctl_blk := p_group_ctl_blk;
          IFEND;
          p_metric_ctl_blk := p_metric_ctl_blk^.metric_chain_link;
        WHILEND;

        { If this group is used by at least one metric,
        { Allocate space for the metric list, and set the group
        { control block to point to it. }

        IF metric_list_index > 0 THEN

          ALLOCATE p_metric_list: [1 .. metric_list_index];
          p_group_ctl_blk^.p_metric_list := p_metric_list;

          { Loop through the metric chain again. This time, fill in
          { the entries in the metric list. }

          metric_list_index := 1;
          p_metric_ctl_blk := metric_chain_head;
          WHILE p_metric_ctl_blk <> NIL DO
            IF p_metric_ctl_blk^.group_name = p_group_ctl_blk^.name THEN
              p_metric_list^ [metric_list_index] := p_metric_ctl_blk;
              metric_list_index := metric_list_index + 1;
            IFEND;
            p_metric_ctl_blk := p_metric_ctl_blk^.metric_chain_link;
          WHILEND;

        IFEND;

        { Find the next group to link. }


        p_group_ctl_blk := p_group_ctl_blk^.group_chain_link;

      WHILEND;
?? EJECT ??
      { Scan through the report control blocks. }

      p_report_ctl_blk := report_chain_head;
      WHILE p_report_ctl_blk <> NIL DO

        CASE p_report_ctl_blk^.report_type OF

        = dump_report, gen_group_file =


          { If a dump report is requested, set the copy flag for the group. }

          find_group (p_report_ctl_blk^.group_name, p_group_ctl_blk);
          IF p_group_ctl_blk = NIL THEN

            osp$set_status_abnormal (pmc$external_log_management_id, pme$undefined_group_for_dump,
                  p_report_ctl_blk^.group_name, local_status);
            check_status (local_status);

          ELSE

            p_report_ctl_blk^.p_group_ctl_blk := p_group_ctl_blk;

            pmp$get_unique_name (file_name, local_status);
            check_status (local_status);
            amp$open (file_name, amc$record, ^file_access_selections, p_group_ctl_blk^.
                  copy_file_identifier, local_status);
            check_status (local_status);

            p_group_ctl_blk^.copy_requested := TRUE;

          IFEND;

        = datades_report =

          find_group (p_report_ctl_blk^.group_name, p_group_ctl_blk);
          IF p_group_ctl_blk = NIL THEN
            osp$set_status_abnormal (pmc$external_log_management_id, pme$undefined_group_for_dump,
                  p_report_ctl_blk^.group_name, local_status);
            check_status (local_status);
          ELSE
            p_group_ctl_blk^.desc_needed := TRUE;
            ALLOCATE temp_p_desc_blk;
            temp_p_desc_blk^.desc_chain_link := NIL;
            temp_p_desc_blk^.count := 0;
            temp_p_desc_blk^.desc_data := ' ';
            temp_p_desc_blk^.desc_data_size := 0;
            p_group_ctl_blk^.p_desc_blk := temp_p_desc_blk;
            p_report_ctl_blk^.p_group_ctl_blk := p_group_ctl_blk;
          IFEND;

        = summary_report, distribution_report =

          find_metric (p_report_ctl_blk^.metric_name, p_report_ctl_blk^.p_metric_ctl_blk);
          IF p_report_ctl_blk^.p_metric_ctl_blk = NIL THEN

            osp$set_status_abnormal (pmc$external_log_management_id, pme$undefined_metric, p_report_ctl_blk^.
                  metric_name, local_status);
            osp$append_status_parameter (osc$status_parameter_delimiter, p_report_ctl_blk^.title.value (1,
                  p_report_ctl_blk^.title.size), local_status);
            check_status (local_status);

          IFEND;

        = time_distribution_report =

          find_metric (p_report_ctl_blk^.metric_name, p_report_ctl_blk^.p_metric_ctl_blk);

          IF p_report_ctl_blk^.p_metric_ctl_blk = NIL THEN
            osp$set_status_abnormal (pmc$external_log_management_id, pme$undefined_metric, p_report_ctl_blk^.
                  metric_name, local_status);
            osp$append_status_parameter (osc$status_parameter_delimiter, p_report_ctl_blk^.title.value (1,
                  p_report_ctl_blk^.title.size), local_status);
            check_status (local_status);
          ELSE
            p_report_ctl_blk^.p_metric_ctl_blk^.time_stamp_needed := TRUE;
          IFEND;

        CASEND;

        p_report_ctl_blk := p_report_ctl_blk^.report_chain_link;

      WHILEND;


    PROCEND link_blocks;
?? EJECT, TITLE := 'PROCEDURE open_segs' ??

    PROCEDURE open_segs;

      VAR
        file_access_selections: [STATIC, READ] array [1 .. 1] of amt$access_selection := [[amc$return_option,
          amc$return_at_close]];

      VAR
        file_name: ost$name,
        p_metric_ctl_blk: ^metric_ctl_blk;

      { Loop through the metric control block chain. }

      p_metric_ctl_blk := metric_chain_head;
      WHILE p_metric_ctl_blk <> NIL DO

        { Set up the segment that will contain elements of this metric. }

        pmp$get_unique_name (file_name, local_status);
        check_status (local_status);
        amp$open (file_name, amc$segment, ^file_access_selections, p_metric_ctl_blk^.file_identifier,
              local_status);
        check_status (local_status);
        amp$get_segment_pointer (p_metric_ctl_blk^.file_identifier, amc$sequence_pointer, p_metric_ctl_blk^.
              element_sequence, local_status);
        check_status (local_status);

        { Initialize the variables in the metric control block that
        { accumulate information about this metric's values. }

        p_metric_ctl_blk^.element_count := 0;
        p_metric_ctl_blk^.maximum := - maximum_integer;
        p_metric_ctl_blk^.minimum := maximum_integer;

        { Find the next metric in the chain. }

        p_metric_ctl_blk := p_metric_ctl_blk^.metric_chain_link;

      WHILEND;


    PROCEND open_segs;
?? EJECT, TITLE := 'PROCEDURE scan_log' ??

    PROCEDURE scan_log;

      VAR
        first_record: boolean,
        task_found,
        job_found: boolean,
        temp_index: integer,
        p_group_ctl_blk: ^group_ctl_blk,
        p_metric_ctl_blk: ^metric_ctl_blk,
        p_header: ^sft$global_log_statistic_header,
        p_counters: sft$counters,
        p_descript: ^sft$descriptive_data;

      { Read the next statistic from the log. }
      first_record := TRUE;

      REPEAT

        get_stat_record (input_file, input_buffer, input_file_position, p_header, p_counters, p_descript,
              local_status);
        check_status (local_status);

        IF input_file_position <> amc$eoi THEN

          IF first_record THEN
            p_log_blk^.start_time := p_header^.date_time;
            first_record := FALSE;
          IFEND;
          p_log_blk^.end_time := p_header^.date_time;

          { Scan the group chain, identifying each group that this
          { statistic is a part of. }

          p_group_ctl_blk := group_chain_head;
          WHILE p_group_ctl_blk <> NIL DO
            IF in_group (p_group_ctl_blk, p_header, p_counters, p_descript) THEN

              { Check the desc data statistics needed for the group. If }
              { needed then update its desc chain. }

              IF p_group_ctl_blk^.desc_needed THEN
                enter_group_desc_data (p_group_ctl_blk, p_header, p_descript);
              IFEND;

              { Check task_succ_list to determine the task_id should be
              { put in the successor's pred_task-list. }

              IF p_group_ctl_blk^.p_task_succ_group_list <> NIL THEN
                FOR temp_index := LOWERBOUND (p_group_ctl_blk^.p_task_succ_group_list^) TO UPPERBOUND
                      (p_group_ctl_blk^.p_task_succ_group_list^) DO
                  add_task_to_succ (p_header^.task_id, p_group_ctl_blk^.p_task_succ_group_list^ [temp_index]);
                FOREND;
              IFEND;

              { Check job_seq_list to determine the job_seq should be
              { put in the successor's pred_job_list }

              IF p_group_ctl_blk^.p_job_succ_group_list <> NIL THEN
                FOR temp_index := LOWERBOUND (p_group_ctl_blk^.p_job_succ_group_list^) TO UPPERBOUND
                      (p_group_ctl_blk^.p_job_succ_group_list^) DO
                  add_job_to_succ (p_header^.job_name, p_group_ctl_blk^.p_job_succ_group_list^ [temp_index]);
                FOREND;
              IFEND;


              { When metric defined and no predecessor task or job,
              { enter_element }

              IF (p_group_ctl_blk^.p_metric_list <> NIL) AND (p_group_ctl_blk^.pred_task_group_name =
                    blank_name) AND (p_group_ctl_blk^.pred_job_group_name = blank_name) THEN
                enter_element (p_group_ctl_blk^.p_metric_list^, p_header, p_counters, p_descript);
              ELSE

                { Check the task_id in pred_task_list }

                IF (p_group_ctl_blk^.p_metric_list <> NIL) AND (p_group_ctl_blk^.pred_task_group_name <>
                      blank_name) AND (p_group_ctl_blk^.p_pred_task_head <> NIL) THEN
                  search_pred_task (p_header, p_group_ctl_blk^.p_pred_task_head, task_found);
                  IF task_found THEN
                    enter_element (p_group_ctl_blk^.p_metric_list^, p_header, p_counters, p_descript);
                  IFEND;
                IFEND;

                { check the job_seq in pred_job_list }

                IF (p_group_ctl_blk^.p_metric_list <> NIL) AND (p_group_ctl_blk^.pred_job_group_name <>
                      blank_name) AND (p_group_ctl_blk^.p_pred_job_head <> NIL) THEN
                  search_pred_job (p_header, p_group_ctl_blk^.p_pred_job_head, job_found);

                  { If element entered because of pred_task found, do not
                  { enter it again. }

                  IF job_found AND (NOT task_found) THEN
                    enter_element (p_group_ctl_blk^.p_metric_list^, p_header, p_counters, p_descript);
                  IFEND;
                IFEND;
              IFEND;


              IF p_group_ctl_blk^.copy_requested THEN

                put_stat_record (p_group_ctl_blk^.copy_file_identifier, p_header, p_counters, p_descript,
                      local_status);
                check_status (local_status);

              IFEND;

            IFEND;

            { Advance to the next group in the chain. }

            p_group_ctl_blk := p_group_ctl_blk^.group_chain_link;

          WHILEND;

        IFEND;

      UNTIL input_file_position = amc$eoi;

    PROCEND scan_log;
?? EJECT, TITLE := 'PROCEDURE add_task_to_succ' ??

    PROCEDURE add_task_to_succ (task_id: ost$global_task_id;
          p_group_blk: ^group_ctl_blk);

      VAR
        temp_p_task_blk: ^pred_task_blk;

      ALLOCATE temp_p_task_blk;
      temp_p_task_blk^.pred_task_link := p_group_blk^.p_pred_task_head;
      temp_p_task_blk^.global_task_id := task_id;
      p_group_blk^.p_pred_task_head := temp_p_task_blk;

    PROCEND add_task_to_succ;
?? EJECT, TITLE := 'PROCEDURE add_job_to_succ' ??

    PROCEDURE add_job_to_succ (job_seq: jmt$system_supplied_name;
          p_group_blk: ^group_ctl_blk);

      VAR
        temp_p_job_blk: ^pred_job_blk;

      ALLOCATE temp_p_job_blk;
      temp_p_job_blk^.pred_job_link := p_group_blk^.p_pred_job_head;
      temp_p_job_blk^.job_seq_number := job_seq;
      p_group_blk^.p_pred_job_head := temp_p_job_blk;

    PROCEND add_job_to_succ;
?? EJECT, TITLE := 'PROCEDURE search_pred_task' ??

    PROCEDURE search_pred_task (sp_header: ^sft$global_log_statistic_header;
      VAR head: ^pred_task_blk;
      VAR found: boolean);

      VAR
        p_current_blk,
        p_previous_blk: ^pred_task_blk;

      p_current_blk := head;
      p_previous_blk := NIL;
      found := FALSE;

      WHILE (p_current_blk <> NIL) AND (NOT found) DO
        IF p_current_blk^.global_task_id = sp_header^.task_id THEN
          found := TRUE;
        ELSE
          p_previous_blk := p_current_blk;
          p_current_blk := p_current_blk^.pred_task_link;
        IFEND;
      WHILEND;

      IF found AND (p_previous_blk = NIL) THEN
        head := head^.pred_task_link;
      ELSE
        IF found THEN
          p_previous_blk^.pred_task_link := p_current_blk^.pred_task_link;
        IFEND;
      IFEND;

      IF found THEN
        FREE p_current_blk;
      IFEND;

    PROCEND search_pred_task;
?? EJECT, TITLE := 'PROCEDURE search_pred_job' ??

    PROCEDURE search_pred_job (sp_header: ^sft$global_log_statistic_header;
      VAR head: ^pred_job_blk;
      VAR found: boolean);

      VAR
        p_current_blk,
        p_previous_blk: ^pred_job_blk;

      p_current_blk := head;
      p_previous_blk := NIL;
      found := FALSE;

      WHILE (p_current_blk <> NIL) AND (NOT found) DO
        IF p_current_blk^.job_seq_number = sp_header^.job_name THEN
          found := TRUE;
        ELSE
          p_previous_blk := p_current_blk;
          p_current_blk := p_current_blk^.pred_job_link;
        IFEND;
      WHILEND;

      IF found AND (p_previous_blk = NIL) THEN
        head := head^.pred_job_link;
      ELSE
        IF found THEN
          p_previous_blk^.pred_job_link := p_current_blk^.pred_job_link;
        IFEND;
      IFEND;

      IF found THEN
        FREE p_current_blk;
      IFEND;

    PROCEND search_pred_job;
?? EJECT, TITLE := 'PROCEDURE enter_element' ??

    PROCEDURE enter_element (input_metric_list: metric_list;
          p_header: ^sft$global_log_statistic_header;
          p_counters: sft$counters;
          p_descript: ^sft$descriptive_data);

      VAR
        date_time_value: ^date_time_metric,
        metric,
        temp_metric: integer,
        p_metric: ^integer,
        metric_index: integer,
        p_metric_ctl_blk: ^metric_ctl_blk;

      { Loop through the metric list. }

   /metric_loop/

      FOR metric_index := LOWERBOUND (input_metric_list) TO UPPERBOUND (input_metric_list) DO

        { Extract the current metric element. }

        p_metric_ctl_blk := input_metric_list [metric_index];
        CASE p_metric_ctl_blk^.metric_type OF
        = counter_metric =
          IF p_metric_ctl_blk^.incremental THEN
            IF p_metric_ctl_blk^.first_element THEN
              p_metric_ctl_blk^.first_element := FALSE;
              p_metric_ctl_blk^.previous_value := p_counters^ [p_metric_ctl_blk^.counter_number];
              CYCLE /metric_loop/;
            ELSE
              temp_metric := p_counters^ [p_metric_ctl_blk^.counter_number] -
                          p_metric_ctl_blk^.previous_value;
              p_metric_ctl_blk^.element_count := p_metric_ctl_blk^.element_count + 1;
              p_metric_ctl_blk^.previous_value := p_counters^ [p_metric_ctl_blk^.counter_number];
            IFEND;
          ELSE
            temp_metric := p_counters^ [p_metric_ctl_blk^.counter_number];
            p_metric_ctl_blk^.element_count := p_metric_ctl_blk^.element_count + 1;
          IFEND;
        = expression_metric =
          temp_metric := 1;
          p_metric_ctl_blk^.element_count := p_metric_ctl_blk^.element_count + 1;
        CASEND;

        { Apply the scale factor to the extracted metric. }
        { round off }

        IF p_metric_ctl_blk^.scale_factor = 1 THEN
          metric := temp_metric;
        ELSE
          metric := temp_metric DIV p_metric_ctl_blk^.scale_factor;
          IF temp_metric MOD p_metric_ctl_blk^.scale_factor >= p_metric_ctl_blk^.scale_factor DIV 2 THEN
            metric := metric + 1;
          IFEND;
        IFEND;

        { Put the metric into the element sequence segment. }

        IF p_metric_ctl_blk^.time_stamp_needed THEN
          NEXT date_time_value IN p_metric_ctl_blk^.element_sequence.sequence_pointer;
          date_time_value^.counter_value := metric;
          date_time_value^.time_value := time_in_seconds (p_header^.date_time);
          date_time_value^.date_value := date_in_days (p_header^.date_time);
        ELSE
          NEXT p_metric IN p_metric_ctl_blk^.element_sequence.sequence_pointer;
          p_metric^ := metric;
        IFEND;

        { Accumulate metric minimum and maximums. }

        IF metric > p_metric_ctl_blk^.maximum THEN
          p_metric_ctl_blk^.maximum := metric;
        IFEND;
        IF metric < p_metric_ctl_blk^.minimum THEN
          p_metric_ctl_blk^.minimum := metric;
        IFEND;

      FOREND /metric_loop/;

    PROCEND enter_element;
?? EJECT, TITLE := 'PROCEDURE enter_group_desc_data' ??

    PROCEDURE enter_group_desc_data (p_group_ctl_blk: ^group_ctl_blk;
          p_header: ^sft$global_log_statistic_header,
          p_descript: ^sft$descriptive_data);

      VAR
        temp_p_desc_blk1,
        temp_p_desc_blk2: ^desc_blk;

      temp_p_desc_blk1 := p_group_ctl_blk^.p_desc_blk;
      temp_p_desc_blk2 := temp_p_desc_blk1^.desc_chain_link;

      IF p_descript = NIL THEN
        temp_p_desc_blk1^.count := temp_p_desc_blk1^.count + 1;
        EXIT enter_group_desc_data;
      ELSE
        insert_to_desc_chain (p_descript, p_header^.descriptive_data_size, temp_p_desc_blk1,
              temp_p_desc_blk2);
      IFEND;

    PROCEND enter_group_desc_data;
?? EJECT, TITLE := 'PROCEDURE generate_reports' ??

    PROCEDURE generate_reports;

      VAR
        p_report_ctl_blk: ^report_ctl_blk;

      print_log_report_title;
      display_log_info;

      p_report_ctl_blk := report_chain_head;
      WHILE p_report_ctl_blk <> NIL DO
        CASE p_report_ctl_blk^.report_type OF
        = summary_report =
          display_summary (p_report_ctl_blk^);

        = dump_report =
          dump_group (p_report_ctl_blk^);

        = distribution_report =
          display_distribution (p_report_ctl_blk^);

        = time_distribution_report =
          display_time_distribution (p_report_ctl_blk^);

        = datades_report =
          display_descriptive_data (p_report_ctl_blk^);

        = gen_group_file =
          generate_file (p_report_ctl_blk^);

        CASEND;
        p_report_ctl_blk := p_report_ctl_blk^.report_chain_link;
      WHILEND;

    PROCEND generate_reports;
?? EJECT, TITLE := 'PROCEDURE display_summary' ??

    PROCEDURE display_summary (ctl_blk: report_ctl_blk);

      VAR
        p_metric: ^integer,
        sum: integer,
        square_sum: integer,
        p_metric_ctl_blk: ^metric_ctl_blk,
        line_image: string (136),
        mean: integer,
        metric_array: ^array [1 .. * ] of date_time_metric,
        metric_value: date_time_metric,
        local_status: ost$status,
        variance: integer,
        element_index: integer;

      { Generate the output report. }

      print_title (ctl_blk, 'Summary Report');

      sum := 0;
      square_sum := 0;

      p_metric_ctl_blk := ctl_blk.p_metric_ctl_blk;
      IF p_metric_ctl_blk^.element_count = 0 THEN
        print (' There are no elements for this metric.');
      ELSE
        RESET p_metric_ctl_blk^.element_sequence.sequence_pointer;

        IF p_metric_ctl_blk^.time_stamp_needed THEN
          NEXT metric_array: [1 .. p_metric_ctl_blk^.element_count] IN p_metric_ctl_blk^.element_sequence.
                sequence_pointer;

          FOR element_index := 1 TO p_metric_ctl_blk^.element_count DO
            metric_value := metric_array^ [element_index];
            sum := sum + metric_value.counter_value;
            square_sum := square_sum + (metric_value.counter_value * metric_value.counter_value);
          FOREND;
        ELSE
          FOR element_index := 1 TO p_metric_ctl_blk^.element_count DO
            NEXT p_metric IN p_metric_ctl_blk^.element_sequence.sequence_pointer;
            sum := sum + p_metric^;
            square_sum := square_sum + p_metric^ * p_metric^;
          FOREND;
        IFEND;

        IF ctl_blk.num = TRUE THEN
           line_image := '                       N = ';
           clp$convert_integer_to_rjstring (p_metric_ctl_blk^.element_count, 10, FALSE, ' ',
              line_image (27, 10), local_status);
           check_status (local_status);
           line_image (38, 8) := 'elements';
           print (line_image);
        IFEND;

        IF ctl_blk.mean = TRUE THEN
           mean := sum DIV p_metric_ctl_blk^.element_count;
           line_image := '0                   Mean = ';
           clp$convert_integer_to_rjstring (mean, 10, FALSE, ' ', line_image (27, 10), local_status);
           check_status (local_status);
           line_image (38, 32) := p_metric_ctl_blk^.unit;
           print (line_image);
        IFEND;

        { Compute and display the standard deviation and variance. }

        IF ctl_blk.variance = TRUE THEN
           IF p_metric_ctl_blk^.element_count > 1 THEN
              variance := (square_sum - p_metric_ctl_blk^.element_count * mean * mean) DIV (p_metric_ctl_blk^.
                   element_count - 1);
              line_image := '0               Variance = ';
              clp$convert_integer_to_rjstring (variance, 10, FALSE, ' ', line_image (27, 20), local_status);
              check_status (local_status);
              print (line_image);
           IFEND;
        IFEND;

        IF ctl_blk.min = TRUE THEN
           line_image := '0                Minimum = ';
           clp$convert_integer_to_rjstring (p_metric_ctl_blk^.minimum, 10, FALSE, ' ', line_image (27, 10),
                 local_status);
           check_status (local_status);
           line_image (38, 32) := p_metric_ctl_blk^.unit;
           print (line_image);
        IFEND;

        IF ctl_blk.max = TRUE THEN
           line_image := '0                Maximum = ';
           clp$convert_integer_to_rjstring (p_metric_ctl_blk^.maximum, 10, FALSE, ' ', line_image (27, 10),
                 local_status);
           check_status (local_status);
           line_image (38, 32) := p_metric_ctl_blk^.unit;
           print (line_image);
        IFEND;

        { Display the sum of all metric elements. }

        IF ctl_blk.sum = TRUE THEN
           line_image := '0                    Sum = ';
           clp$convert_integer_to_rjstring (sum, 10, FALSE, ' ', line_image (27, 10), local_status);
           check_status (local_status);
           line_image (38, 32) := p_metric_ctl_blk^.unit;
           print (line_image);
        IFEND;

      IFEND;

    PROCEND display_summary;

?? EJECT, TITLE := 'PROCEDURE display_descriptive_data' ??

    PROCEDURE display_descriptive_data (ctl_blk: report_ctl_blk);

      VAR
        p_temp_desc_blk1,
        p_temp_desc_blk2: ^desc_blk,
        largest_count,
        scale,
        position,
        temp_index,
        print_desc_index,
        print_desc_size,
        line_count,
        page_count: integer,
        new_page: boolean,
        count_base_line,
        divider_line,
        divider_line1,
        divider_line2,
        count_data_line: string (126),
        local_status: ost$status,
        temp_str: ost$string;

      print_title (ctl_blk, 'Descriptive Data Report');

      p_temp_desc_blk1 := ctl_blk.p_group_ctl_blk^.p_desc_blk;
      p_temp_desc_blk2 := p_temp_desc_blk1^.desc_chain_link;

      count_data_line := '  Total Number of Blank Descriptive Data Count  =';
      clp$convert_integer_to_rjstring (p_temp_desc_blk1^.count, 10, FALSE, ' ', count_data_line (50, 9),
            local_status);

{  Find the largest count in the chain  }
      largest_count := 0;
      WHILE p_temp_desc_blk2 <> NIL DO
        IF p_temp_desc_blk2^.count > largest_count THEN
          largest_count := p_temp_desc_blk2^.count;
        IFEND;
        p_temp_desc_blk2 := p_temp_desc_blk2^.desc_chain_link;
      WHILEND;

      IF largest_count = 0 THEN
        IF p_temp_desc_blk1^.count = 0 THEN
          print ('0 ***  There is no elements for this group');
        ELSE
          print (count_data_line);
          print ('0 ***  There is no other descriptive data');
        IFEND;
        RETURN;
      ELSE
        print (count_data_line);
      IFEND;
      p_temp_desc_blk1 := p_temp_desc_blk1^.desc_chain_link;

{  Calculate the scale by dividing 5  }
      IF largest_count MOD 5 <> 0 THEN
        largest_count := largest_count + (largest_count MOD 5);
      IFEND;
      IF largest_count < 5 THEN
        largest_count := 5;
      IFEND;
      scale := largest_count DIV 5;

      count_base_line := '                    DESCRIPTIVE DATA';
      count_base_line (63, 5) := 'COUNT';
      FOR temp_index := 1 TO 6 DO
        clp$convert_integer_to_string ((temp_index - 1) * scale, 10, FALSE, temp_str, local_status);
        count_base_line ((temp_index - 1) * 10 + 72, temp_str.size) := temp_str.value (1, temp_str.size);
      FOREND;

      divider_line := '  ';
      FOR temp_index := 2 TO 123 DO
        IF (temp_index MOD 10 = 2) AND (temp_index > 70) THEN
          divider_line (temp_index) := '+';
        ELSE
          divider_line (temp_index) := '-';
        IFEND;
      FOREND;

      page_count := 1;
      line_count := 0;
      print (count_base_line);
      print (divider_line);
      new_page := FALSE;
      divider_line1 := '  ';
      divider_line1 (2) := '|';
      divider_line1 (59) := '|';
      divider_line1 (71) := '|';
      divider_line1 (123) := '|';
      divider_line2 := ' ';
      FOR temp_index := 2 TO 123 DO
        divider_line2 (temp_index) := '-';
      FOREND;

      WHILE p_temp_desc_blk1 <> NIL DO
        IF new_page THEN
          print_title (ctl_blk, 'Descriptive Data Report ( Cont. )');
        IFEND;

        IF new_page THEN
          print (count_base_line);
          print (divider_line);
          new_page := FALSE;
        IFEND;

        count_data_line := '  ';
        IF p_temp_desc_blk1^.count <> 0 THEN
          print_desc_size := p_temp_desc_blk1^.desc_data_size;
          IF print_desc_size > 0 THEN
            IF print_desc_size > 56 THEN
              print_desc_size := 56;
            IFEND;
            count_data_line (2) := '|';
            count_data_line (3, print_desc_size) := p_temp_desc_blk1^.desc_data (1, print_desc_size);
            count_data_line (59) := '|';
            clp$convert_integer_to_rjstring (p_temp_desc_blk1^.count, 10, FALSE, ' ', count_data_line (60, 9),
                  local_status);
          ELSE
            count_data_line := ' ( NO DESCRIPTIVE DATA )';
          IFEND;

          { Calculate the graph position }

          count_data_line (71) := '|';
          count_data_line (123) := '|';
          position := (p_temp_desc_blk1^.count * 10) DIV scale;
          IF ((p_temp_desc_blk1^.count * 10) MOD scale) > (scale DIV 2) THEN
            position := position + 1;
          IFEND;
          FOR temp_index := 0 TO position DO
            count_data_line (temp_index + 72) := '*';
          FOREND;
          print (count_data_line);
          line_count := line_count + 1;

          IF p_temp_desc_blk1^.desc_data_size > 56 THEN
            count_data_line := ' |';
            count_data_line (59) := '|';
            count_data_line (71) := '|';
            count_data_line (123) := '|';
            print_desc_index := 57;
            REPEAT
              print_desc_size := p_temp_desc_blk1^.desc_data_size - print_desc_index + 1;
              IF print_desc_size > 56 THEN
                print_desc_size := 56;
              IFEND;
              count_data_line (3, 56) := p_temp_desc_blk1^.desc_data (print_desc_index, print_desc_size);
              print (count_data_line);
              line_count := line_count + 1;
              print_desc_index := print_desc_index + print_desc_size;
            UNTIL print_desc_index > p_temp_desc_blk1^.desc_data_size;
          IFEND;

          print (divider_line1);
          line_count := line_count + 1;
          IF line_count > 40 THEN
            print (divider_line2);
            line_count := 0;
            page_count := page_count + 1;
            new_page := TRUE;
          IFEND;
        IFEND;

        p_temp_desc_blk1 := p_temp_desc_blk1^.desc_chain_link;

      WHILEND;
      print (divider_line2);

    PROCEND display_descriptive_data;

?? EJECT, TITLE := 'PROCEDURE dump_group' ??

    PROCEDURE dump_group (ctl_blk: report_ctl_blk);

      VAR
         local_status: ost$status;


      amp$rewind (ctl_blk.p_group_ctl_blk^.copy_file_identifier, osc$wait, local_status);
      check_status (local_status);

      { Generate the report. }

      print_title (ctl_blk, 'Group Dump');


      REPEAT
        get_stat_record (ctl_blk.p_group_ctl_blk^.copy_file_identifier, input_buffer, input_file_position,
              p_stat_header, p_stat_counters, p_stat_descript, local_status);
        check_status (local_status);

        IF input_file_position <> amc$eoi THEN
          dump_record (p_stat_header, p_stat_counters, p_stat_descript, ^ctl_blk, local_status);
          check_status (local_status);
        IFEND;

      UNTIL input_file_position = amc$eoi;

    PROCEND dump_group;
?? EJECT, TITLE := 'PROCEDURE generate_file' ??

    PROCEDURE generate_file (ctl_blk: report_ctl_blk);

      VAR
        gf_access_selections: [STATIC, READ] array [1 .. 4] of amt$access_selection := [[amc$open_position,
          amc$open_no_positioning], [amc$file_contents, amc$legible], [amc$page_format, amc$continuous_form],
          [amc$page_width, 80]],
        group_file_attributes: [STATIC, READ] array [1 .. 3] of amt$file_item := [[amc$file_contents,
          amc$legible], [amc$page_format, amc$continuous_form], [amc$page_width, 80]],
        group_file_identifier: amt$file_identifier,
        cycle_selector: pft$cycle_selector;

      amp$rewind (ctl_blk.p_group_ctl_blk^.copy_file_identifier, osc$wait, local_status);
      check_status (local_status);

{  Create a new file or new cycle  }

      IF ctl_blk.permanent THEN
        group_file_path [3] := ctl_blk.file_name;
        cycle_selector.cycle_option := pfc$highest_cycle;
        pfp$define (ctl_blk.file_name, group_file_path, cycle_selector, blank_passw, 999, pfc$log,
              local_status);
        check_status (local_status);
      IFEND;

      IF ctl_blk.file_name <> default_output THEN
        amp$file (ctl_blk.file_name, group_file_attributes, local_status);
        check_status (local_status);
        amp$open (ctl_blk.file_name, amc$record, ^gf_access_selections, group_file_identifier, local_status);
        check_status (local_status);
      ELSE
        group_file_identifier := output_file;
      IFEND;

      REPEAT
        get_stat_record (ctl_blk.p_group_ctl_blk^.copy_file_identifier, input_buffer, input_file_position,
              p_stat_header, p_stat_counters, p_stat_descript, local_status);
        check_status (local_status);

        IF input_file_position <> amc$eoi THEN
          convert_log_to_gf_format (p_stat_header, p_stat_counters, p_stat_descript, group_file_identifier,
                local_status);
          check_status (local_status);
        IFEND;
      UNTIL input_file_position = amc$eoi;

      IF ctl_blk.file_name <> default_output THEN
        amp$close (group_file_identifier, local_status);
        check_status (local_status);
      IFEND;

    PROCEND generate_file;

?? EJECT, TITLE := 'PROCEDURE display_distribution' ??

    PROCEDURE display_distribution (VAR ctl_blk: report_ctl_blk);

      VAR

{  cnt_time_frame is the graph to be printed  }

        cnt_time_frame: array [1 .. 31] of string (116),
        time_base_line: string (126),
        high_line,
        low_line,
        msg_line: string (126),
        high_frame_line,
        low_frame_line: string (116),

{  distribution_array[ 1 ][ 1 .. 101 ] - 101 points are selected for }
{    CP response time according to users' selection or by default. }
{    defaults are maximum and minimum of the metric.               }
{  distribution_array[ 2 ][ 1 .. 101 ] - 101 counts for each time    }
{    points.                                                       }
{  distribution_array[ 3 ][ 1 .. 101 ] - 101 points for count axis.  }
{  distribution_array[ 4 ][ 1 .. 101 ] - the count_axis for 101      }
{    counts                                                        }

        distribution_array: array [1 .. 4] of array [1 .. 101] of integer,
        frame_scale,
        frame_factor: integer,
        p_metric: ^integer,
        p_metric_ctl_blk: ^metric_ctl_blk,
        out_low_x,
        out_high_x,
        in_frame_cnt,
        out_low_y,
        out_high_y: integer,
        frame_index,
        temp_index: integer,
        temp_str: ost$string,
        local_status: ost$status,
        x_int,
        half_x_int1,
        half_x_int2,
        y_int: integer,
        count_limit_exceed,
        y_low_default,
        y_high_default: boolean,
        x_high_low_equal,
        y_high_low_equal: boolean;

?? EJECT, TITLE := 'PROCEDURE set_up_x_ints ( sub proc )' ??

      PROCEDURE set_up_x_ints;

{  This procedure set up the time interval according to the high-low  }
{  time limits and count the elements in each time interval.  If high }
{  limit - low limit MOD 10 <> 0, then high limit will be patched to  }
{  make it = 0.  There are always 10 time intervals.  }
{ }

        VAR
          element_index,
          patch_to_high: integer;

        FOR temp_index := 1 TO 4 DO
          FOR frame_index := 1 TO 101 DO
            distribution_array [temp_index] [frame_index] := 0;
          FOREND;
        FOREND;

        in_frame_cnt := p_metric_ctl_blk^.element_count;
        out_low_x := 0;
        out_high_x := 0;

{  Check the time high low limits.  If not given, use defaults  }

        IF ctl_blk.x_low_limit < 0 THEN
          ctl_blk.x_low_limit := p_metric_ctl_blk^.minimum;
        IFEND;
        IF ctl_blk.x_high_limit < 0 THEN
          ctl_blk.x_high_limit := p_metric_ctl_blk^.maximum;
        IFEND;

{  Check high - low > 0.  If not, error  }

        IF ctl_blk.x_high_limit - ctl_blk.x_low_limit < 0 THEN
          osp$set_status_abnormal (pmc$external_log_management_id, pme$bad_high_low_limit,
            'BAD TIME HIGH LOW LIMIT', local_status);
          check_status (local_status);
        IFEND;

        IF ctl_blk.x_high_limit - ctl_blk.x_low_limit = 0 THEN
          ctl_blk.x_high_limit := ctl_blk.x_low_limit + 10;
          ctl_blk.x_interval := large;
          x_high_low_equal := TRUE;
        IFEND;

        IF ctl_blk.x_interval = self_adjust THEN
          IF ctl_blk.x_high_limit - ctl_blk.x_low_limit < 11 THEN
            frame_scale := 10;
          ELSE
            IF ctl_blk.x_high_limit - ctl_blk.x_low_limit < 501 THEN
              frame_scale := 20;
            ELSE
              frame_scale := 100;
            IFEND;
          IFEND;
        ELSE
          CASE ctl_blk.x_interval OF
          = large =
            frame_scale := 10;
          = medium =
            frame_scale := 20;
          = small =
            frame_scale := 100;
          CASEND;
        IFEND;

        CASE frame_scale OF
        = 10 =
          frame_factor := 10;
        = 20 =
          frame_factor := 5;
        = 100 =
          frame_factor := 1;
        CASEND;

        patch_to_high := (ctl_blk.x_high_limit - ctl_blk.x_low_limit) MOD frame_scale;
        IF patch_to_high <> 0 THEN
          patch_to_high := frame_scale - patch_to_high;
        IFEND;

        x_int := (ctl_blk.x_high_limit + patch_to_high - ctl_blk.x_low_limit) DIV frame_scale;
        half_x_int1 := x_int DIV 2;
        IF x_int MOD 2 = 0 THEN
          half_x_int2 := half_x_int1 - 1;
          IF half_x_int2 < 0 THEN
            half_x_int2 := 0;
          IFEND;
        ELSE
          half_x_int2 := half_x_int1;
        IFEND;

        FOR temp_index := 1 TO frame_scale + 1 DO
          distribution_array [1] [temp_index] := ctl_blk.x_low_limit + (temp_index - 1) * x_int;
        FOREND;

        RESET p_metric_ctl_blk^.element_sequence.sequence_pointer;
        FOR element_index := 1 TO p_metric_ctl_blk^.element_count DO
          NEXT p_metric IN p_metric_ctl_blk^.element_sequence.sequence_pointer;
          IF p_metric^ < ctl_blk.x_low_limit THEN
            out_low_x := out_low_x + 1;
          ELSE
            IF p_metric^ > ctl_blk.x_high_limit + patch_to_high THEN
              out_high_x := out_high_x + 1;
            ELSE

            /find_its_int/
              FOR temp_index := 1 TO frame_scale + 1 DO
                IF p_metric^ <= distribution_array [1] [temp_index] + half_x_int2 THEN
                  distribution_array [2] [temp_index] := distribution_array [2] [temp_index] + 1;
                  EXIT /find_its_int/;
                IFEND;
              FOREND /find_its_int/;
            IFEND;
          IFEND;
        FOREND;
        in_frame_cnt := in_frame_cnt - out_high_x - out_low_x;

      PROCEND set_up_x_ints;

?? EJECT, TITLE := 'PROCEDURE set_up_y_ints ( sub proc )' ??

      PROCEDURE set_up_y_ints;

        VAR
          max_cnt,
          min_cnt: integer,
          patch_to_high,
          y_temp: integer;

        IF ctl_blk.cnt_high_limit < 0 THEN
          y_high_default := TRUE;
          max_cnt := distribution_array [2] [1];
          FOR temp_index := 2 TO frame_scale + 1 DO
            IF max_cnt < distribution_array [2] [temp_index] THEN
              max_cnt := distribution_array [2] [temp_index];
            IFEND;
          FOREND;
          ctl_blk.cnt_high_limit := max_cnt;
        IFEND;
        IF ctl_blk.cnt_low_limit < 0 THEN
          y_low_default := TRUE;
          min_cnt := distribution_array [2] [1];
          FOR temp_index := 2 TO frame_scale + 1 DO
            IF min_cnt > distribution_array [2] [temp_index] THEN
              min_cnt := distribution_array [2] [temp_index];
            IFEND;
          FOREND;
          ctl_blk.cnt_low_limit := min_cnt;
        IFEND;

        IF ctl_blk.cnt_high_limit - ctl_blk.cnt_low_limit < 0 THEN
          osp$set_status_abnormal (pmc$external_log_management_id, pme$bad_high_low_limit,
            'BAD COUNT HIGH LOW LIMITS', local_status);
          check_status (local_status);
        IFEND;

        IF ctl_blk.cnt_high_limit - ctl_blk.cnt_low_limit = 0 THEN
          ctl_blk.cnt_high_limit := ctl_blk.cnt_low_limit + 10;
          y_high_low_equal := TRUE;
        IFEND;

        patch_to_high := (ctl_blk.cnt_high_limit - ctl_blk.cnt_low_limit) MOD 10;
        IF patch_to_high <> 0 THEN
          patch_to_high := 10 - patch_to_high;
        IFEND;
        y_int := (ctl_blk.cnt_high_limit + patch_to_high - ctl_blk.cnt_low_limit) DIV 10;
        FOR temp_index := 1 TO 11 DO
          distribution_array [3] [temp_index] := ctl_blk.cnt_low_limit + (temp_index - 1) * y_int;
        FOREND;

        FOR temp_index := 1 TO frame_scale + 1 DO
          IF distribution_array [2] [temp_index] >= ctl_blk.cnt_low_limit - y_int DIV 2 THEN
            y_temp := ((distribution_array [2] [temp_index] - ctl_blk.cnt_low_limit) * 30) DIV (y_int * 10) +
                  1;
            IF ((distribution_array [2] [temp_index] - ctl_blk.cnt_low_limit) * 30) MOD (y_int * 10) >= y_int
                  * 5 THEN
              y_temp := y_temp + 1;
            IFEND;
          ELSE
            y_temp := - 1;
          IFEND;
          distribution_array [4] [temp_index] := y_temp;
        FOREND;

      PROCEND set_up_y_ints;

?? EJECT, TITLE := 'PROCEDURE reset_x_bounds' ??

      PROCEDURE reset_x_bounds;

        VAR
          first_max,
          second_max,
          first_index,
          second_index: integer,
          temp_max,
          temp,
          old_x_span,
          adjustment: integer;

        old_x_span := distribution_array [1] [frame_scale + 1] - distribution_array [1] [1];
        first_max := distribution_array [2] [1];
        first_index := 1;
        FOR temp_index := 2 TO frame_scale + 1 DO
          IF first_max < distribution_array [2] [temp_index] THEN
            first_max := distribution_array [2] [temp_index];
            first_index := temp_index;
          IFEND;
        FOREND;

        IF ctl_blk.display_option = second_max_centered THEN
          temp_index := first_index - 2;
          second_max := 0;
          second_index := 0;
          IF temp_index >= 1 THEN
            IF distribution_array [2] [1] >= distribution_array [2] [2] THEN
              second_max := distribution_array [2] [1];
              second_index := 1;
            IFEND;
            WHILE temp_index > 1 DO
              IF (distribution_array [2] [temp_index] >= distribution_array [2] [temp_index - 1]) AND
                    (distribution_array [2] [temp_index] >= distribution_array [2] [temp_index + 1]) AND
                    (distribution_array [2] [temp_index] > second_max) THEN
                second_max := distribution_array [2] [temp_index];
                second_index := temp_index;
              IFEND;
              temp_index := temp_index - 1;
            WHILEND;
          IFEND;
          temp_index := first_index + 2;
          IF temp_index <= frame_scale + 1 THEN
            IF (distribution_array [2] [frame_scale + 1] >= distribution_array [2] [frame_scale]) AND
                  (distribution_array [2] [frame_scale + 1] > second_max) THEN
              second_max := distribution_array [2] [frame_scale + 1];
              second_index := frame_scale + 1;
            IFEND;
            WHILE temp_index < frame_scale + 1 DO
              IF (distribution_array [2] [temp_index] >= distribution_array [2] [temp_index - 1]) AND
                    (distribution_array [2] [temp_index] >= distribution_array [2] [temp_index + 1]) AND
                    (distribution_array [2] [temp_index] > second_max) THEN
                second_max := distribution_array [2] [temp_index];
                second_index := temp_index;
              IFEND;
              temp_index := temp_index + 1;
            WHILEND;
          IFEND;
        IFEND;

        IF ctl_blk.display_option = first_max_centered THEN
          adjustment := (old_x_span * 10) DIV 100;
          temp := first_index;
        ELSE
          IF second_index = 0 THEN
            print ('0   No second maximum can be found, first maximum centered');
            adjustment := (old_x_span * 10) DIV 100;
            temp := first_index;
          ELSE
            adjustment := (old_x_span * 20) DIV 100;
            temp := second_index;
          IFEND;
        IFEND;

        ctl_blk.x_high_limit := distribution_array [1] [temp] + adjustment;
        ctl_blk.x_low_limit := distribution_array [1] [temp] - adjustment;
        IF ctl_blk.x_high_limit > p_metric_ctl_blk^.maximum THEN
          ctl_blk.x_high_limit := p_metric_ctl_blk^.maximum;
        IFEND;
        IF ctl_blk.x_low_limit < p_metric_ctl_blk^.minimum THEN
          ctl_blk.x_low_limit := p_metric_ctl_blk^.minimum;
        IFEND;
        IF y_low_default THEN
          ctl_blk.cnt_low_limit := - 1;
        IFEND;
        IF y_high_default THEN
          ctl_blk.cnt_high_limit := - 1;
        IFEND;

      PROCEND reset_x_bounds;

?? EJECT, TITLE := 'PROCEDURE display_distribution ( Main )' ??

      print_title (ctl_blk, 'Distribution Report');

      p_metric_ctl_blk := ctl_blk.p_metric_ctl_blk;
      IF p_metric_ctl_blk^.element_count = 0 THEN
        print (' There are no elements for this metric.');
        RETURN;
      IFEND;

      y_low_default := FALSE;
      y_high_default := FALSE;
      x_high_low_equal := FALSE;
      y_high_low_equal := FALSE;

      FOR temp_index := 1 TO 31 DO
        cnt_time_frame [temp_index] := '  ';
      FOREND;

      set_up_x_ints;
      set_up_y_ints;

{  Check the display option  }

      IF ctl_blk.display_option <> max_min_bound THEN
        reset_x_bounds;
        set_up_x_ints;
        set_up_y_ints;
      IFEND;

      high_line := '  ';
      low_line := '  ';
      high_line (35, * ) := 'Number of Elements above X-axis High Limit  =';
      low_line (35, * ) := 'Number of Elements below X-axis Low  Limit  =';
      clp$convert_integer_to_rjstring (out_high_x, 10, FALSE, ' ', high_line (82, 7), local_status);
      check_status (local_status);
      clp$convert_integer_to_rjstring (out_low_x, 10, FALSE, ' ', low_line (82, 7), local_status);
      print (high_line);
      print (low_line);

      count_limit_exceed := FALSE;
      high_frame_line := '0 ';
      low_frame_line := '0 ';
      out_low_y := 0;
      out_high_y := 0;
      FOR temp_index := 1 TO frame_scale + 1 DO
        IF distribution_array [4] [temp_index] > 31 THEN
          out_high_y := out_high_y + distribution_array [2] [temp_index];
          high_frame_line ((temp_index - 1) * frame_factor + 16) := 'H';
          count_limit_exceed := TRUE;
        IFEND;
        IF distribution_array [4] [temp_index] < 1 THEN
          out_low_y := out_low_y + distribution_array [2] [temp_index];
          low_frame_line ((temp_index - 1) * frame_factor + 16) := 'L';
          count_limit_exceed := TRUE;
        IFEND;
      FOREND;
      in_frame_cnt := in_frame_cnt - out_low_y - out_high_y;

      high_line := '  ';
      low_line := '  ';
      msg_line := '  ';
      high_line (35, * ) := 'Number of Elements above Y-axis High Limit  =';
      low_line (35, * ) := 'Number of Elements below Y-axis Low  Limit  =';
      msg_line (35, * ) := 'Number of Elements within the Frame Limits  =';
      clp$convert_integer_to_rjstring (out_high_y, 10, FALSE, ' ', high_line (82, 7), local_status);
      check_status (local_status);
      IF x_high_low_equal OR y_high_low_equal THEN
        high_line (92, 8) := 'WARNING:';
      IFEND;
      clp$convert_integer_to_rjstring (out_low_y, 10, FALSE, ' ', low_line (82, 7), local_status);
      check_status (local_status);
      IF x_high_low_equal THEN
        low_line (92, * ) := 'X high and low limits are equal';
      IFEND;
      clp$convert_integer_to_rjstring (in_frame_cnt, 10, FALSE, ' ', msg_line (82, 7), local_status);
      check_status (local_status);
      IF y_high_low_equal THEN
        msg_line (92, * ) := 'Y high and low limits are equal';
      IFEND;
      print (high_line);
      print (low_line);
      print (msg_line);

      FOR temp_index := 1 TO 10 DO
        cnt_time_frame [1] (temp_index * 10 + 7, 10) := '---------+';
        cnt_time_frame [31] (temp_index * 10 + 7, 10) := '---------+';
      FOREND;

      FOR frame_index := 1 TO 31 DO

        IF frame_index MOD 3 = 1 THEN
          clp$convert_integer_to_rjstring (distribution_array [3] [frame_index DIV 3 + 1], 10, FALSE, ' ',
                cnt_time_frame [frame_index] (6, 10), local_status);
          check_status (local_status);
          cnt_time_frame [frame_index] (16) := '+';
          cnt_time_frame [frame_index] (116) := '+';
        ELSE
          cnt_time_frame [frame_index] (16) := '|';
          cnt_time_frame [frame_index] (116) := '|';
        IFEND;

        FOR temp_index := 1 TO frame_scale + 1 DO
          IF (frame_index >= 2) AND (distribution_array [4] [temp_index] >= frame_index) THEN
            cnt_time_frame [frame_index] ((temp_index - 1) * frame_factor + 16) := '*';
          IFEND;
        FOREND;

      FOREND;
      cnt_time_frame [31] (1) := '0';


      time_base_line := '  ';
      FOR temp_index := 1 TO 11 DO
        clp$convert_integer_to_string (distribution_array [1] [(temp_index - 1) * (10 DIV frame_factor) + 1],
              10, FALSE, temp_str, local_status);
        time_base_line ((temp_index - 1) * 10 + 16, temp_str.size) := temp_str.value (1, temp_str.size);
        check_status (local_status);
      FOREND;

      print (high_frame_line);
      frame_index := 31;
      REPEAT
        print (cnt_time_frame [frame_index]);
        frame_index := frame_index - 1;
      UNTIL frame_index = 0;
      print (time_base_line);
      print (low_frame_line);

      msg_line := '  ';
      msg_line (55, max_name_size) := p_metric_ctl_blk^.unit (1, max_name_size);
      print (msg_line);

      IF count_limit_exceed THEN
        print ('0               NOTES:');
        print ('                    H - The value on y-axis correspond to x-interval');
        print ('                        is higher than the y-axis upper bound');
        print ('                    L - The value on y-axis correspond to x-interval');
        print ('                        is lower than the y-axis lower bound');
      IFEND;

    PROCEND display_distribution;
?? EJECT, TITLE := 'PROCEDURE display_time_distribution' ??

    PROCEDURE display_time_distribution (ctl_blk: report_ctl_blk);

      CONST
        number_of_seconds_in_day = 86400;

      VAR
        distribution_array: array [1 .. 6] of array [1 .. 101] of integer,

{ distribution_array[1] [1 .. 101] - 101 points are selected on X-axis   }
{     for time intervals; this value is either given by the user or by   }
{     default.  The default is the beginning and ending date and time    }
{     of the log being processed.                                        }
{ distribution_array[2] [1 .. 101] - 101 values giving the lowest value  }
{     seen of the metric in the corresponding time interval.             }
{ distribution_array[3] [1 .. 101] - 101 values giving the highest value }
{     seen of the metric in the corresponding time interval.             }
{ distribution_array[4] [1 .. 101] - 101 points are selected on Y-axis   }
{     for element intervals; the interval is determined by the metric_   }
{     limits given on the display_time_distribution subcommand. Only     }
{     11 of these entries are used.                                      }
{ distribution_array[5] [1 .. 101] - 101 values giving the lowest value  }
{     to be used on the Y-axis for the corresponding time interval.      }
{ distribution_array[6] [1 .. 101] - 101 values giving the highest value }
{     to be used on the Y-axis for the corresponding time interval.      }

        graph: array [1 .. 31] of string (116);

?? EJECT, NEWTITLE := '  PROCEDURE initialize_arrays' ??

      PROCEDURE initialize_arrays;

        VAR
          i: 1 .. 6,
          j: 1 .. 101;

{ initialize distribution array }

        FOR i := 1 TO 6 DO
          IF (i = 2) THEN
            FOR j := 1 TO 101 DO
              distribution_array [i] [j] := maximum_integer;
            FOREND;
          ELSE
            FOR j := 1 TO 101 DO
              distribution_array [i] [j] := 0;
            FOREND;
          IFEND;
        FOREND;

{ initialize graph array }

        FOR j := 1 TO 31 DO
          graph [j] := ' ';
        FOREND;

      PROCEND initialize_arrays;

?? OLDTITLE ??
?? EJECT, NEWTITLE := '  PROCEDURE find_limits_for_date_and_time' ??

      PROCEDURE find_limits_for_date_and_time (VAR starting_date: integer;
        VAR ending_date: integer;
        VAR starting_time: integer;
        VAR ending_time: integer);


        VAR
          default_ending_date: integer,
          default_ending_time: integer,
          default_starting_date: integer,
          default_starting_time: integer,
          p_log_ctl_blk: ^input_log_blk,
          temp_date: integer,
          temp_time: integer;


        default_starting_date := maximum_integer;
        default_starting_time := maximum_integer;
        default_ending_date := 0;
        default_ending_time := 0;


        IF p_metric_ctl_blk^.p_group_ctl_blk^.date_specified THEN
          starting_date := date_in_days (p_metric_ctl_blk^.p_group_ctl_blk^.start_dt);
          ending_date := date_in_days (p_metric_ctl_blk^.p_group_ctl_blk^.start_dt);
        ELSE
          p_log_ctl_blk := log_chain_head;

          WHILE p_log_ctl_blk <> NIL DO
            temp_date := date_in_days (p_log_ctl_blk^.start_time);
            IF temp_date < default_starting_date THEN
              default_starting_date := temp_date;
            IFEND;
            temp_date := date_in_days (p_log_ctl_blk^.end_time);
            IF temp_date > default_ending_date THEN
              default_ending_date := temp_date;
            IFEND;
            p_log_ctl_blk := p_log_ctl_blk^.log_chain_link;
          WHILEND;

          starting_date := default_starting_date;
          ending_date := default_ending_date;
        IFEND;


        IF p_metric_ctl_blk^.p_group_ctl_blk^.time_specified THEN
          starting_time := time_in_seconds (p_metric_ctl_blk^.p_group_ctl_blk^.start_dt);
          ending_time := time_in_seconds (p_metric_ctl_blk^.p_group_ctl_blk^.end_dt);
        ELSE
          p_log_ctl_blk := log_chain_head;

          WHILE p_log_ctl_blk <> NIL DO
            temp_time := time_in_seconds (p_log_ctl_blk^.start_time);
            IF temp_time < default_starting_time THEN
              default_starting_time := temp_time;
            IFEND;
            temp_time := time_in_seconds (p_log_ctl_blk^.end_time);
            IF temp_time > default_ending_time THEN
              default_ending_time := temp_time;
            IFEND;
            p_log_ctl_blk := p_log_ctl_blk^.log_chain_link;
          WHILEND;

          starting_time := default_starting_time;
          ending_time := default_ending_time;
        IFEND;

      PROCEND find_limits_for_date_and_time;

?? OLDTITLE ??
?? EJECT, NEWTITLE := '  PROCEDURE set_up_x_axis' ??

      PROCEDURE set_up_x_axis (VAR x_high_low_equal: boolean;
        VAR time_interval: integer;
        VAR frame_scale: 1 .. 100;
        VAR starting_time: integer;
        VAR ending_time: integer);

        VAR
          ending_date: integer,
          index: 1 .. 101,
          patch_to_high: 0 .. 100,
          starting_date: integer;


        starting_date := 0;
        ending_date := 0;
        starting_time := 0;
        ending_time := 0;

        find_limits_for_date_and_time (starting_date, ending_date, starting_time, ending_time);

        IF (starting_date = ending_date) AND (starting_time = ending_time) THEN
          x_high_low_equal := TRUE;
          ending_time := starting_time + 10;
        IFEND;

        starting_time := number_of_seconds_in_day * starting_date + starting_time;
        ending_time := number_of_seconds_in_day * ending_date + ending_time;

        IF (ending_time - starting_time) < 11 THEN
          frame_scale := 10;
        ELSE
          IF (ending_time - starting_time) < 20 THEN
            frame_scale := 20;
          ELSE
            frame_scale := 100;
          IFEND;
        IFEND;

        patch_to_high := (ending_time - starting_time) MOD frame_scale;
        IF patch_to_high <> 0 THEN
          patch_to_high := frame_scale - patch_to_high;
        IFEND;

        time_interval := ((ending_time + patch_to_high) - starting_time) DIV frame_scale;

        FOR index := 1 TO frame_scale + 1 DO
          distribution_array [1] [index] := starting_time + ((index - 1) * time_interval);
        FOREND;

      PROCEND set_up_x_axis;

?? OLDTITLE ??
?? EJECT, NEWTITLE := '  PROCEDURE set_up_y_axis' ??

      PROCEDURE set_up_y_axis (VAR y_high_low_equal: boolean;
        VAR y_interval: integer);

        VAR
          index: 1 .. 101,
          patch_to_high: 0 .. 10,
          y_high_limit: integer,
          y_low_limit: integer;

        y_low_limit := ctl_blk.metric_low_limit;
        y_high_limit :=ctl_blk.metric_high_limit;


        IF y_low_limit = y_high_limit THEN
          y_high_limit := y_low_limit + 10;
          y_high_low_equal := TRUE;
        IFEND;

        patch_to_high := (y_high_limit - y_low_limit) MOD 10;
        IF patch_to_high <> 0 THEN
          patch_to_high := 10 - patch_to_high;
        IFEND;

        y_interval := ((y_high_limit + patch_to_high) - y_low_limit) DIV 10;

        FOR index := 1 TO 11 DO
          distribution_array [4] [index] := y_low_limit + ((index - 1) * y_interval);
        FOREND;

      PROCEND set_up_y_axis;
?? OLDTITLE ??
?? EJECT, NEWTITLE := '  PROCEDURE fill_in_distribution_array' ??

      PROCEDURE fill_in_distribution_array (p_metric_ctl_blk: ^metric_ctl_blk;
            y_interval: integer;
            time_interval: integer;
            frame_scale: 1 .. 100;
            starting_time: integer;
            ending_time: integer;
        VAR out_low_x: integer;
        VAR out_low_y: integer;
        VAR out_high_x: integer;
        VAR out_high_y: integer);


        VAR
          element_index: integer,
          half_time_interval: integer,
          high_element_value: integer,
          highest_value_on_y_axis: integer,
          index: 1 .. 101,
          low_element_value: integer,
          lowest_value_on_y_axis: integer,
          metric_array: ^array [1 .. * ] of date_time_metric,
          metric_value: date_time_metric,
          temp_time_value: integer,
          y_high_limit: integer,
          y_low_limit: integer,
          y_temp: integer;

        y_low_limit := ctl_blk.metric_low_limit;
        y_high_limit :=ctl_blk.metric_high_limit;

        lowest_value_on_y_axis := y_low_limit - (y_interval DIV 2);
        highest_value_on_y_axis := y_high_limit + (y_interval DIV 2);

        half_time_interval := time_interval DIV 2;

        RESET p_metric_ctl_blk^.element_sequence.sequence_pointer;

        NEXT metric_array: [1 .. p_metric_ctl_blk^.element_count] IN p_metric_ctl_blk^.element_sequence.
              sequence_pointer;

        FOR element_index := 1 TO p_metric_ctl_blk^.element_count DO
          metric_value := metric_array^ [element_index];
          temp_time_value := (metric_value.date_value * number_of_seconds_in_day) + metric_value.time_value;
          IF temp_time_value < starting_time THEN
            out_low_x := out_low_x + 1;
          ELSE
            IF temp_time_value > ending_time THEN
              out_high_x := out_high_x + 1;
            ELSE

            /find_its_interval/
              FOR index := 1 TO frame_scale DO
                IF ((distribution_array [1] [index] - half_time_interval) <= temp_time_value) AND
                      ((distribution_array [1] [index + 1] - half_time_interval) > temp_time_value) THEN
                  IF metric_value.counter_value < lowest_value_on_y_axis THEN
                    distribution_array [5] [index] := - 1;
                    out_low_y := out_low_y + 1;
                  ELSE
                    IF metric_value.counter_value > highest_value_on_y_axis THEN
                      distribution_array [6] [index] := - 1;
                      out_high_y := out_high_y + 1;
                    ELSE
                      IF metric_value.counter_value < distribution_array [2] [index] THEN
                        distribution_array [2] [index] := metric_value.counter_value;
                      IFEND;

                      IF metric_value.counter_value > distribution_array [3] [index] THEN
                        distribution_array [3] [index] := metric_value.counter_value;
                      IFEND;

                    IFEND;
                  IFEND;

                  EXIT /find_its_interval/;
                IFEND;
              FOREND /find_its_interval/;

            IFEND;
          IFEND;
        FOREND;


        FOR index := 1 TO frame_scale + 1 DO
          low_element_value := distribution_array [2] [index];
          IF (distribution_array [5] [index] <> - 1) AND (low_element_value <> maximum_integer) THEN
            y_temp := ((low_element_value - y_low_limit) * 30) DIV (y_interval * 10) + 1;
            IF ((low_element_value - y_low_limit) * 30) MOD (y_interval * 10) >= (y_interval * 5) THEN
              y_temp := y_temp + 1;
            IFEND;
            distribution_array [5] [index] := y_temp;
          IFEND;

          high_element_value := distribution_array [3] [index];
          IF (distribution_array [6] [index] <> - 1) AND (high_element_value <> 0) THEN
            y_temp := ((high_element_value - y_low_limit) * 30) DIV (y_interval * 10) + 1;
            IF ((high_element_value - y_low_limit) * 30) MOD (y_interval * 10) >= (y_interval * 5) THEN
              y_temp := y_temp + 1;
            IFEND;
            distribution_array [6] [index] := y_temp;
          IFEND;

        FOREND;

      PROCEND fill_in_distribution_array;

?? OLDTITLE ??
?? EJECT, NEWTITLE := '  PROCEDURE fill_in_graph_array' ??

      PROCEDURE fill_in_graph_array (frame_scale: 1 .. 100;
            frame_factor: 1 .. 10;
        VAR high_frame_line: string (116);
        VAR low_frame_line: string (116));

        VAR
          local_status: ost$status,
          y_index: 1 .. 31,
          x_index: 1 .. 116;

        FOR x_index := 1 TO 10 DO
          graph [1] (x_index * 10 + 7, 10) := '---------+';
          graph [31] (x_index * 10 + 7, 10) := '---------+';
        FOREND;

        FOR y_index := 1 TO 31 DO
          IF (y_index MOD 3) = 1 THEN
            clp$convert_integer_to_rjstring (distribution_array [4] [(y_index DIV 3) + 1], 10, FALSE, ' ',
                  graph [y_index] (6, 10), local_status);
            check_status (local_status);
            graph [y_index] (16) := '+';
            graph [y_index] (116) := '+';
          ELSE
            graph [y_index] (16) := '|';
            graph [y_index] (116) := '|';
          IFEND;
        FOREND;

        FOR x_index := 1 TO frame_scale + 1 DO
          IF distribution_array [5] [x_index] = - 1 THEN
            low_frame_line ((x_index - 1) * frame_factor + 16) := 'L';
          IFEND;
          IF distribution_array [6] [x_index] = - 1 THEN
            high_frame_line ((x_index - 1) * frame_factor + 16) := 'H';
          IFEND;
        FOREND;

        FOR x_index := 1 TO frame_scale + 1 DO
          FOR y_index := 1 TO 31 DO
            IF (distribution_array [5] [x_index] <= y_index) AND (distribution_array [6] [x_index] >= y_index)
                  THEN
              graph [y_index] ((x_index - 1) * frame_factor + 16) := '*';
            IFEND;
          FOREND;
        FOREND;

        graph [31] (1) := '0';

      PROCEND fill_in_graph_array;

?? OLDTITLE ??
?? EJECT, NEWTITLE := '  PROCEDURE calculate_date_time_lines' ??

      PROCEDURE calculate_date_time_lines (starting_time: integer;
            ending_time: integer;
            frame_scale: 1 .. 100;
            frame_factor: 1 .. 10;
        VAR time_base_line: string (126);
        VAR date_base_line: string (126));

        VAR
          date: 0 .. 365,
          frame_constant: 1 .. 10,
          hours: 0 .. 23,
          index: 1 .. 11,
          last_date: 0 .. 365,
          local_status: ost$status,
          minutes: 0 .. 59,
          seconds: 0 .. 59,
          temp_time_string: string (8),
          temp_time_value: integer,
          time: integer;

        last_date := 0;
        frame_constant := 10 DIV frame_factor;
        temp_time_string (3) := ':';
        temp_time_string (6) := ':';

        FOR index := 1 TO 11 DO
          temp_time_value := distribution_array [1] [(index - 1) * (frame_constant) + 1];
          date := temp_time_value DIV number_of_seconds_in_day;
          time := temp_time_value - (date * number_of_seconds_in_day);

          IF date <> last_date THEN
            last_date := date;
            clp$convert_integer_to_rjstring (date, 10, FALSE, '0', date_base_line (index * 10 + 6, 3),
                  local_status);
            check_status (local_status);
          IFEND;

          hours := time DIV 3600;
          minutes := (time - (hours * 3600)) DIV 60;
          seconds := (time - (hours * 3600) - (minutes * 60));

          clp$convert_integer_to_rjstring (hours, 10, FALSE, '0', temp_time_string (1, 2), local_status);
          check_status (local_status);

          clp$convert_integer_to_rjstring (minutes, 10, FALSE, '0', temp_time_string (4, 2), local_status);
          check_status (local_status);

          clp$convert_integer_to_rjstring (seconds, 10, FALSE, '0', temp_time_string (7, 2), local_status);
          check_status (local_status);

          time_base_line (index * 10 + 3, 8) := temp_time_string;

        FOREND;

      PROCEND calculate_date_time_lines;

?? OLDTITLE ??
?? EJECT ??

      VAR
        date_base_line: string (126),
        ending_time: integer,
        frame_scale: 1 .. 100,
        frame_factor: 1 .. 10,
        high_frame_line: string (116),
        in_frame_cnt: integer,
        local_status: ost$status,
        low_frame_line: string (116),
        out_low_x: integer,
        out_high_x: integer,
        out_low_y: integer,
        out_high_y: integer,
        p_metric_ctl_blk: ^metric_ctl_blk,
        starting_time: integer,
        time_base_line: string (126),
        time_interval: integer,
        unit_message_line: string (126),
        x_high_low_equal: boolean,
        y_high_low_equal: boolean,
        y_index: 1 .. 31,
        y_interval: integer;

      VAR
        x_axis_high_limit_msg: [STATIC] string (126) :=
          '                                 Number of Elements above X-axis High Limit  =',
        x_axis_low_limit_msg: [STATIC] string (126) :=
          '                                 Number of Elements below X-axis Low  Limit  =',
        y_axis_high_limit_msg: [STATIC] string (126) :=
          '                                 Number of Elements above Y-axis High Limit  =',
        y_axis_low_limit_msg: [STATIC] string (126) :=
          '                                 Number of Elements below Y-axis Low  Limit  =',
        points_within_graph_msg: [STATIC] string (126) :=
          '                                 Number of Elements within the Frame Limits  =';

?? EJECT ??

      print_title (ctl_blk, 'Time Distribution Report');

      p_metric_ctl_blk := ctl_blk.p_metric_ctl_blk;
      IF p_metric_ctl_blk^.element_count = 0 THEN
        print ('There are no elements for this metric.');
        RETURN;
      IFEND;

      initialize_arrays;

      out_low_x := 0;
      out_high_x := 0;
      x_high_low_equal := FALSE;
      out_low_y := 0;
      out_high_y := 0;
      y_high_low_equal := FALSE;

      set_up_x_axis (x_high_low_equal, time_interval, frame_scale, starting_time, ending_time);
      set_up_y_axis (y_high_low_equal, y_interval);

      fill_in_distribution_array (p_metric_ctl_blk, y_interval, time_interval, frame_scale, starting_time,
            ending_time, out_low_x, out_low_y, out_high_x, out_high_x);

      clp$convert_integer_to_rjstring (out_high_x, 10, FALSE, ' ', x_axis_high_limit_msg (82, 7),
            local_status);
      check_status (local_status);

      clp$convert_integer_to_rjstring (out_low_x, 10, FALSE, ' ', x_axis_low_limit_msg (82, 7), local_status);
      check_status (local_status);

      print (x_axis_high_limit_msg);
      print (x_axis_low_limit_msg);

      IF x_high_low_equal OR y_high_low_equal THEN
        y_axis_high_limit_msg (92, 8) := 'WARNING:';
        IF x_high_low_equal THEN
          y_axis_low_limit_msg (92, * ) := 'X high and low limits are equal';
        ELSE
          y_axis_low_limit_msg (92, * ) := 'Y high and low limits are equal';
        IFEND;
      IFEND;

      clp$convert_integer_to_rjstring (out_high_y, 10, FALSE, ' ', y_axis_high_limit_msg (82, 7),
            local_status);
      check_status (local_status);

      clp$convert_integer_to_rjstring (out_low_y, 10, FALSE, ' ', y_axis_low_limit_msg (82, 7), local_status);
      check_status (local_status);

      in_frame_cnt := p_metric_ctl_blk^.element_count - out_low_y - out_low_x - out_high_y - out_high_x;

      clp$convert_integer_to_rjstring (in_frame_cnt, 10, FALSE, ' ', points_within_graph_msg (82, 7),
            local_status);
      check_status (local_status);

      print (y_axis_high_limit_msg);
      print (y_axis_low_limit_msg);
      print (points_within_graph_msg);

      CASE frame_scale OF
      = 10 =
        frame_factor := 10;
      = 20 =
        frame_factor := 5;
      = 100 =
        frame_factor := 1;
      CASEND;

      high_frame_line := '0 ';
      low_frame_line := '0 ';

      fill_in_graph_array (frame_scale, frame_factor, high_frame_line, low_frame_line);

      print (high_frame_line);

      FOR y_index := 31 DOWNTO 1 DO
        print (graph [y_index]);
      FOREND;

      time_base_line := ' ';
      date_base_line := ' ';

      calculate_date_time_lines (starting_time, ending_time, frame_scale, frame_factor, time_base_line,
            date_base_line);

      print (time_base_line);
      print (date_base_line);
      print (low_frame_line);

      unit_message_line := ' ';
      unit_message_line (55, max_name_size) := p_metric_ctl_blk^.unit (1, max_name_size);
      print (unit_message_line);

      IF p_metric_ctl_blk^.element_count <> in_frame_cnt THEN
        print ('0               NOTES:');
        print ('                    H - The value on y-axis correspond to x-interval');
        print ('                        is higher than the y-axis upper bound');
        print ('                    L - The value on y-axis correspond to x-interval');
        print ('                        is lower than the y-axis lower bound');
      IFEND;

    PROCEND display_time_distribution;
?? EJECT, TITLE := 'Procedure condition_handler' ??

    PROCEDURE Condition_Handler (condition: pmt$condition;
       condition_descriptor: ^pmt$condition_information;
       save_area: ^ost$stack_frame_save_area;
       VAR status: ost$status);

      program_status := abnormal_status;
      EXIT lgp$display_binary_log;
    PROCEND Condition_handler;
?? EJECT, TITLE := 'Main Program' ??

    VAR
       establish_descriptor: pmt$established_handler;

    pmp$establish_condition_handler (abnormal_condition, ^condition_handler, ^establish_descriptor,
       program_status);
    IF NOT program_status.normal THEN
       RETURN;
    IFEND;

    initialize;


{  Set up the command utility environment, and start processing
{  subcommands.                                                  }

    clp$push_utility ('DISPLAY_BINARY_LOG             ', clc$global_command_search, sub_command_list, NIL,
          local_status);
    check_status (local_status);

    clp$scan_command_file (clc$current_command_input, 'DISPLAY_BINARY_LOG             ', 'DISBL',
          local_status);
    check_status (local_status);

{  Clean up after the user has entered a QUIT command.  }

    clp$pop_utility (local_status);
    check_status (local_status);

{  Link all of the control blocks set up by the subcommands.  }

    link_blocks;
    open_segs;
    p_log_blk := log_chain_head;
    WHILE p_log_blk <> NIL DO
      amp$open (p_log_blk^.log_file_name, amc$record, p_access_array, input_file, local_status);
      check_status (local_status);
      scan_log;
      amp$close (input_file, local_status);
      check_status (local_status);
      p_log_blk := p_log_blk^.log_chain_link;
    WHILEND;
    generate_reports;
    close_files;
  PROCEND lgp$display_binary_log;
?? OLDTITLE, TITLE := 'Common Procedures', NEWTITLE := '  ' ??
?? EJECT, TITLE := 'PROCEDURE check_status' ??

    PROCEDURE check_status (input_status: ost$status);

      IF NOT input_status.normal THEN
        close_files;
        abnormal_status := input_status;
        pmp$cause_condition (abnormal_status_condition, NIL, local_status);
      IFEND;

    PROCEND check_status;
?? EJECT, TITLE := 'PROCEDURE find_group' ??

  PROCEDURE find_group (group_name: name_type;
    VAR p_group_ctl_blk: ^group_ctl_blk);

    p_group_ctl_blk := group_chain_head;

    WHILE p_group_ctl_blk <> NIL DO
      IF p_group_ctl_blk^.name = group_name THEN
        RETURN;
      IFEND;
      p_group_ctl_blk := p_group_ctl_blk^.group_chain_link;
    WHILEND;

  PROCEND find_group;
?? EJECT, TITLE := 'print_log_report_title' ??

    PROCEDURE print_log_report_title;

      VAR
        line_image: string (132);

      print ('1 Logs Scanned by Display_Binary_Log');
      line_image := '  Display_Binary_Log        ';
      print (line_image);
      print ('-');
      print ('-');

    PROCEND print_log_report_title;
?? EJECT, TITLE := 'PROCEDURE close_files' ??

    PROCEDURE close_files;

      VAR
        local_status: ost$status,
        p_group_ctl_blk: ^group_ctl_blk,
        p_metric_ctl_blk: ^metric_ctl_blk;

      amp$close (output_file, local_status);


{ Now closing all metric files.

      p_metric_ctl_blk := metric_chain_head;
      WHILE p_metric_ctl_blk <> NIL DO

        amp$close (p_metric_ctl_blk^.file_identifier, local_status);

        p_metric_ctl_blk := p_metric_ctl_blk^.metric_chain_link;

      WHILEND;

{ Now closing all group files.

      p_group_ctl_blk := group_chain_head;
      WHILE p_group_ctl_blk <> NIL DO

        amp$close (p_group_ctl_blk^.copy_file_identifier, local_status);

        p_group_ctl_blk := p_group_ctl_blk^.group_chain_link;

      WHILEND;

    PROCEND close_files;
?? EJECT, TITLE := 'PROCEDURE convert_date_time' ??

    PROCEDURE convert_date_time (date_time: ost$date_time;
      VAR str: string (20));

      VAR
        year: integer;

      IF date_time.year > 99 THEN
        year := date_time.year - 100;
      ELSE
        year := date_time.year;
      IFEND;
      clp$convert_integer_to_rjstring (year, 10, FALSE, '0', str (1, 2), local_status);
      check_status (local_status);
      clp$convert_integer_to_rjstring (date_time.month, 10, FALSE, '0', str (4, 2), local_status);
      check_status (local_status);
      clp$convert_integer_to_rjstring (date_time.day, 10, FALSE, '0', str (7, 2), local_status);
      check_status (local_status);
      str (3) := '/';
      str (6) := '/';

      clp$convert_integer_to_rjstring (date_time.hour, 10, FALSE, '0', str (11, 2), local_status);
      check_status (local_status);
      clp$convert_integer_to_rjstring (date_time.minute, 10, FALSE, '0', str (14, 2), local_status);
      check_status (local_status);
      clp$convert_integer_to_rjstring (date_time.second, 10, FALSE, '0', str (17, 2), local_status);
      check_status (local_status);
      str (13) := ':';
      str (16) := ':';

    PROCEND convert_date_time;
?? EJECT, TITLE := 'PROCEDURE print' ??

    PROCEDURE print (text_line: string ( * ));

      VAR
        line_length: integer;

      line_length := #SIZE (text_line);

      WHILE (line_length > 1) AND (text_line (line_length) = ' ') DO
        line_length := line_length - 1;
      WHILEND;


      amp$put_next (output_file, #LOC (text_line), line_length, file_byte_address, local_status);
      check_status (local_status);

    PROCEND print;
?? EJECT, TITLE := 'PROCEDURE emit_statistics_report' ??

  PROCEDURE emit_statistics_report;
    VAR
      stat_blk: ^ sft$global_log_statistic_header,
      p_counters: sft$counters,
      p_descript: ^sft$descriptive_data,
      first_record: boolean,
      start_time,
      end_time: ost$date_time,
      local_status: ost$status,
      line_buffer: string (130);

    first_record := true;
    repeat
      get_stat_record (input_file, input_buffer, input_file_position, stat_blk, p_counters,
                       p_descript, local_status);
      check_status (local_status);
      IF input_file_position <> amc$eoi THEN
         IF first_record THEN
            first_record := false;
            start_time := stat_blk^.date_time;
         IFEND;
         end_time := stat_blk^.date_time;
         insert_into_code_list (stat_blk);
      IFEND;
    UNTIL input_file_position = amc$eoi;
    print_log_report_title;
    print_time_date_stat_hdr (start_time, end_time);
    print_code;
  PROCEND emit_statistics_report;
?? EJECT, TITLE := 'PROCEDURE insert_into_code_list' ??

  PROCEDURE insert_into_code_list (stat_blk: ^sft$global_log_statistic_header);

    VAR
       p_stat_code_ctl_blk: ^stat_code_ctl_blk,
       found_code: boolean,
       q,
       p: ^stat_code_ctl_blk;

    found_code := false;
    q := NIL;
    p := stat_name_chain_head;
    /find_code/
    WHILE p <> NIL DO
       IF p^.stat_code < stat_blk^.statistic_code THEN
          q := p;
          p := p^.code_chain_link;
       ELSEIF p^.stat_code > stat_blk^.statistic_code THEN
          EXIT /find_code/;
       ELSE
          found_code := true;
          EXIT /find_code/;
       IFEND;
     WHILEND /find_code/;

     IF NOT found_code THEN
        ALLOCATE p_stat_code_ctl_blk;
        p_stat_code_ctl_blk^.stat_code := stat_blk^.statistic_code;
        p_stat_code_ctl_blk^.code_chain_link := p;
        IF q = NIL THEN
           stat_name_chain_head := p_stat_code_ctl_blk;
        ELSE
           q^.code_chain_link := p_stat_code_ctl_blk;
        IFEND;
     IFEND;
  PROCEND insert_into_code_list;
?? EJECT, TITLE := 'PROCEDURE print_time_date_stat_hdr' ??

  PROCEDURE print_time_date_stat_hdr (start_time : ost$date_time;
    end_time : ost$date_time);

    VAR
       line_image: string (136),
       str1,
       str2: string (20);

    convert_date_time (start_time, str1);
    convert_date_time (end_time, str2);

    line_image := '   DATE : ';
    line_image (32,7) := 'TIME : ';
    line_image (19,2) := '..';
    line_image (49,2) := '..';
    line_image (11,8) := str1 (1,8);
    line_image (21,8) := str2 (1,8);
    line_image (41,8) := str1 (11,8);
    line_image (51,8) := str2 (11,8);
    print (line_image);
  PROCEND print_time_date_stat_hdr;
?? EJECT, TITLE := 'PROCEDURE print_code' ??

  PROCEDURE print_code;

    VAR
       statistic_string: string (10),
       buffer: string (130),
       buf_length: integer,
       q: ^stat_code_ctl_blk;

    q := stat_name_chain_head;
    buffer := ' ';
    buffer := '  STATISTICS ';
    print (buffer);
    WHILE q <> NIL DO
      buffer := ' ';
      get_statistic_string (q^.stat_code, statistic_string, local_status);
      IF NOT local_status.normal THEN
         RETURN;
      IFEND;
      STRINGREP (buffer, buf_length, '            ', statistic_string);
      print (buffer);
      q := q^.code_chain_link;
    WHILEND;
  PROCEND print_code;
?? EJECT, TITLE := 'PROCEDURE find_metric' ??

  PROCEDURE find_metric (metric_name: name_type;
    VAR p_metric_ctl_blk: ^metric_ctl_blk);

    p_metric_ctl_blk := metric_chain_head;

    WHILE p_metric_ctl_blk <> NIL DO
      IF p_metric_ctl_blk^.name = metric_name THEN
        RETURN;
      IFEND;
      p_metric_ctl_blk := p_metric_ctl_blk^.metric_chain_link;
    WHILEND;

  PROCEND find_metric;
?? EJECT, TITLE := 'PROCEDURE [INLINE] get_statistic_string' ??

  PROCEDURE [INLINE] get_statistic_string (statistic: sft$statistic_code;
    VAR statistic_string: string (10);
    VAR status: ost$status);

    VAR
      statistic_id: ost$status_identifier,
      statistic_number: ost$status_condition_number,
      num_string: ost$string,
      str_length: integer,
      str_value: ost$name;

    statistic_string := ' ';
    osp$unpack_status_condition (statistic, statistic_id, statistic_number);

    clp$convert_integer_to_string (statistic_number, 10, false, num_string, status);
    IF NOT status.normal THEN
      return;
    IFEND;

    STRINGREP (str_value, str_length, statistic_id, num_string.value(1, num_string.size));
    statistic_string := str_value (1, str_length);

  PROCEND get_statistic_string;
?? EJECT, TITLE := 'PROCEDURE dump_record' ??

  PROCEDURE dump_record (p_header: ^sft$global_log_statistic_header;
        p_counters: sft$counters;
        p_descript: ^sft$descriptive_data;
        report_ctl_blk: ^report_ctl_blk;
    VAR local_status: ost$status);

    VAR
      i: 0 .. 1,
      line_image: string (136),
      line_length: integer,
      statistic_string: string (10),
      counter_counter: 0 .. sfc$max_number_of_counters,
      line_position: integer;

    VAR
      stat_date: ost$date,
      stat_time: ost$time,
      task_id_index: string(5),
      task_id_seqno: string(3);

    { Dump the statistic record header }

    line_image := ' ';

    get_statistic_string (p_header^.statistic_code, statistic_string, local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;

    pmp$format_compact_date (p_header^.date_time, osc$mdy_date, stat_date, local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;

    pmp$format_compact_time (p_header^.date_time, osc$millisecond_time, stat_time, local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;


    clp$convert_integer_to_rjstring (p_header^.task_id.index, 10, FALSE, ' ', task_id_index,
          local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;


    clp$convert_integer_to_rjstring (p_header^.task_id.seqno, 10, FALSE, '0', task_id_seqno,
          local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;

    STRINGREP (line_image, line_length, ' ', statistic_string, '  ', stat_date.mdy,
      '  ', stat_time.millisecond, '  ', p_header^.job_name (1, jmc$system_supplied_name_size),
      ' ', task_id_index, '-', task_id_seqno);

    amp$put_next (output_file, ^line_image, line_length, file_byte_address, local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;

    line_image := ' ';

    { Dump the descriptive data, if any }

    IF p_header^.descriptive_data_size > 0 THEN
      IF p_header^.descriptive_data_size > 128 THEN
        line_image (2, 128) := p_descript^;
        amp$put_next (output_file, ^line_image, #SIZE (line_image), file_byte_address, local_status);
        IF NOT local_status.normal THEN
          RETURN;
        IFEND;
        line_image := ' ';
        line_image (2, *) := p_descript^ (129, p_header^.descriptive_data_size - 128);
        amp$put_next (output_file, ^line_image, #SIZE (line_image), file_byte_address, local_status);
        IF NOT local_status.normal THEN
          RETURN;
        IFEND;
      ELSE
        line_image (2, p_header^.descriptive_data_size) := p_descript^;
        amp$put_next (output_file, ^line_image, #SIZE (line_image), file_byte_address, local_status);
        IF NOT local_status.normal THEN
          RETURN;
        IFEND;
      IFEND;
    IFEND;

    { Dump all of the counters }

    counter_counter := 1;
    line_position := 2;
    line_image := ' ';

    WHILE counter_counter <= p_header^.number_of_counters DO

      clp$convert_integer_to_rjstring (p_counters^ [counter_counter], report_ctl_blk^.counter_radix
            [counter_counter], TRUE, ' ', line_image (line_position, 25), local_status);
      IF NOT local_status.normal THEN
        RETURN;
      IFEND;
      line_position := line_position + 25;
      counter_counter := counter_counter + 1;
      IF line_position > (4 * 25) THEN
        amp$put_next (output_file, ^line_image, #SIZE (line_image), file_byte_address, local_status);
        IF NOT local_status.normal THEN
          RETURN;
        IFEND;
        line_position := 2;
        line_image := ' ';
      IFEND;
    WHILEND;

    IF line_position > 2 THEN
      amp$put_next (output_file, ^line_image, #SIZE (line_image), file_byte_address, local_status);
      IF NOT local_status.normal THEN
        RETURN;
      IFEND;
    IFEND;

    { Output a blank line to separate statistics }

    line_image (1) := ' ';
    amp$put_next (output_file, ^line_image (1), #SIZE (line_image (1)), file_byte_address,
          local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;


  PROCEND dump_record;
?? EJECT, TITLE := 'PROCEDURE convert_log_to_gf_format' ??

  PROCEDURE convert_log_to_gf_format (p_header: ^sft$global_log_statistic_header;
        p_counters: sft$counters;
        p_descript: ^sft$descriptive_data;
        gf_identifier: amt$file_identifier;
    VAR local_status: ost$status);

    VAR
      i: 0 .. 1,
      line_image: string (136),
      month: 0 .. 12,
      year: 0 .. 255,
      day: 1 .. 366,
      year_string: string (4),
      day_string: string (3),
      hour: string (2),
      minute: string (2),
      second: string (2),
      millisecond: string (3),
      number_of_counters: string (2),
      descriptive_data_size: string (3),
      task_id_index: string (5),
      task_id_seqno: string (3),
      line_length: integer,
      statistic_string: string (10),
      counter_counter: 0 .. sfc$max_number_of_counters,
      line_position: 1 .. 136;

    day := p_header^.date_time.day;
    month := p_header^.date_time.month - 1;
    year := p_header^.date_time.year;

    line_image := '  ';
    get_statistic_string (p_header^.statistic_code, statistic_string, local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;

    clp$convert_integer_to_rjstring (year + 1900, 10, FALSE, '0', year_string, local_status);
    WHILE month >= 1 DO
      CASE month OF
      = 1, 3, 5, 7, 8, 10, 12 =
        day := day + 31;

      = 4, 6, 9, 11 =
        day := day + 30;

      = 2 =
        IF (year MOD 4) = 0 THEN
          day := day + 29;
        ELSE
          day := day + 28;
        IFEND;
      CASEND;
      month := month - 1;
    WHILEND;
    clp$convert_integer_to_rjstring (day, 10, FALSE, '0', day_string, local_status);
    clp$convert_integer_to_rjstring (p_header^.date_time.hour, 10, FALSE, '0', hour, local_status);
    clp$convert_integer_to_rjstring (p_header^.date_time.minute, 10, FALSE, '0', minute, local_status);
    clp$convert_integer_to_rjstring (p_header^.date_time.second, 10, FALSE, '0', second, local_status);
    clp$convert_integer_to_rjstring (p_header^.date_time.millisecond, 10, FALSE, '0', millisecond,
          local_status);
    clp$convert_integer_to_rjstring (p_header^.task_id.index, 10, FALSE, '0', task_id_index, local_status);
    clp$convert_integer_to_rjstring (p_header^.task_id.seqno, 10, FALSE, '0', task_id_seqno,
          local_status);
    clp$convert_integer_to_rjstring (p_header^.number_of_counters, 10, FALSE, ' ',
          number_of_counters, local_status);
    clp$convert_integer_to_rjstring (p_header^.descriptive_data_size, 10, FALSE, ' ',
          descriptive_data_size, local_status);

    STRINGREP (line_image, line_length, ' ', statistic_string, ' ', year_string, day_string, ' ',
          hour, ':', minute, ':', second, '.', millisecond, ' ', p_header^.job_name (1,
          jmc$system_supplied_name_size), ' ', task_id_index, '-', task_id_seqno, ' ',
          number_of_counters, ' ', descriptive_data_size);

    amp$put_next (gf_identifier, ^line_image, line_length, file_byte_address, local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;

    line_image := '  ';
    counter_counter := 1;
    line_position := 1;
    WHILE p_header^.number_of_counters >= counter_counter DO
      clp$convert_integer_to_rjstring (p_counters^ [counter_counter], 10, FALSE, ' ', line_image
            (line_position, 20), local_status);
      IF (counter_counter MOD 4) = 0 THEN
        amp$put_next (gf_identifier, ^line_image, #SIZE (line_image), file_byte_address, local_status);
        line_position := 1;
        line_image := '  ';
      ELSE
        line_position := line_position + 20;
      IFEND;
      counter_counter := counter_counter + 1;
    WHILEND;
    IF (p_header^.number_of_counters MOD 4) <> 0 THEN
      amp$put_next (gf_identifier, ^line_image, #SIZE (line_image), file_byte_address, local_status);
    IFEND;

    line_image := '  ';
    IF p_header^.descriptive_data_size > 0 THEN
      IF p_header^.descriptive_data_size > 128 THEN
        line_image (2, 128) := p_descript^;
        amp$put_next (gf_identifier, ^line_image, #SIZE (line_image), file_byte_address, local_status);
        IF NOT local_status.normal THEN
          RETURN;
        IFEND;
        line_image := ' ';
        line_image (2, *) := p_descript^ (129, p_header^.descriptive_data_size - 128);
        amp$put_next (gf_identifier, ^line_image, #SIZE (line_image), file_byte_address, local_status);
        IF NOT local_status.normal THEN
          RETURN;
        IFEND;
      ELSE
        line_image (2, p_header^.descriptive_data_size) := p_descript^;
        amp$put_next (gf_identifier, ^line_image, #SIZE (line_image), file_byte_address, local_status);
        IF NOT local_status.normal THEN
          RETURN;
        IFEND;
      IFEND;
    IFEND;

  PROCEND convert_log_to_gf_format;
?? EJECT, TITLE := 'PROCEDURE get_stat_record' ??

  PROCEDURE get_stat_record (file: amt$file_identifier;
    VAR buffer: sft$statistic_buffer;
    VAR file_position: amt$file_position;
    VAR p_header: ^sft$global_log_statistic_header;
    VAR p_counters: sft$counters;
    VAR p_descript: ^sft$descriptive_data;
    VAR local_status: ost$status);

    VAR
      transfer_count: amt$transfer_count,
      record_byte_address: amt$file_byte_address,
      p_buffer: ^sft$statistic_buffer;

    amp$get_next (file, #LOC (buffer), #SIZE (buffer), transfer_count, record_byte_address, file_position,
          local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;

    IF file_position <> amc$eoi THEN
      lgp$parse_statistic (^buffer, p_header, p_counters, p_descript, local_status);
    IFEND;

  PROCEND get_stat_record;
?? EJECT, TITLE := 'PROCEDURE put_stat_record' ??

  PROCEDURE put_stat_record (file: amt$file_identifier;
        p_header: ^sft$global_log_statistic_header;
        p_counters: sft$counters;
        p_descript: ^sft$descriptive_data;
    VAR local_status: ost$status);

    VAR
      record_size: integer,
      record_byte_address: amt$file_byte_address;

    { Note: This procedure assumes that the elements pointed to by the
    { various parameters are part of the same statistic within a single
    { buffer. }

    record_size := #SIZE (p_header^);
    IF p_counters <> NIL THEN
      record_size := record_size + #SIZE (p_counters^);
    IFEND;
    IF p_descript <> NIL THEN
      record_size := record_size + #SIZE (p_descript^);
    IFEND;

    amp$put_next (file, #LOC (p_header^), record_size, record_byte_address, local_status);

  PROCEND put_stat_record;
?? EJECT, TITLE := 'PROCEDURE link_report' ??

  PROCEDURE link_report (p_report_ctl_blk: ^report_ctl_blk);

    VAR
      p_last_block: ^report_ctl_blk;

    { Since the blocks are linked in the order they appear in
    { the command list, we must first find the last block on the
    { chain. }

    p_last_block := report_chain_head;
    IF p_last_block = NIL THEN
      report_chain_head := p_report_ctl_blk;
    ELSE
      WHILE p_last_block^.report_chain_link <> NIL DO
        p_last_block := p_last_block^.report_chain_link;
      WHILEND;

      p_last_block^.report_chain_link := p_report_ctl_blk;
    IFEND;

    p_report_ctl_blk^.report_chain_link := NIL;

  PROCEND link_report;
?? EJECT, TITLE := 'FUNCTION local_name_conflict' ??

  FUNCTION local_name_conflict (file_name: amt$local_file_name): boolean;

    VAR
      p_block: ^report_ctl_blk;

    { This function is used to detect local file name redefined caused }
    { by gengf subcommand when parameter PERMANENT = TRUE. }

    local_name_conflict := FALSE;
    p_block := report_chain_head;

    WHILE p_block <> NIL DO
      IF p_block^.report_type = gen_group_file THEN
        IF p_block^.file_name = file_name THEN
          local_name_conflict := TRUE;
          RETURN;
        IFEND;
      IFEND;
      p_block := p_block^.report_chain_link;
    WHILEND;

  FUNCEND local_name_conflict;

?? EJECT, TITLE := 'PROCEDURE insert_to_desc_chain' ??

  PROCEDURE insert_to_desc_chain (p_descript: ^sft$descriptive_data;
        d_size: 0 .. sfc$max_descriptive_data_size;
    VAR p_desc_blk1,
        p_desc_blk2: ^desc_blk);

    VAR
      found: boolean,
      temp_index: integer,
      p_temp_desc_blk: ^desc_blk;

    found := FALSE;

  /search_order/
    WHILE p_desc_blk2 <> NIL DO
      IF (d_size = p_desc_blk2^.desc_data_size) AND (p_descript^ (1, d_size) = p_desc_blk2^.desc_data (1,
            d_size)) THEN
        p_desc_blk2^.count := p_desc_blk2^.count + 1;
        found := TRUE;
        EXIT /search_order/;
      ELSE
        IF smaller_than (p_descript^, p_desc_blk2^.desc_data, d_size, p_desc_blk2^.desc_data_size) THEN
          EXIT /search_order/;
        IFEND;
      IFEND;
      p_desc_blk1 := p_desc_blk2;
      p_desc_blk2 := p_desc_blk1^.desc_chain_link;
    WHILEND /search_order/;

    IF NOT found THEN
      ALLOCATE p_temp_desc_blk;
      p_temp_desc_blk^.count := 1;
      p_temp_desc_blk^.desc_data (1, d_size) := p_descript^ (1, d_size);
      p_temp_desc_blk^.desc_data_size := d_size;
      p_temp_desc_blk^.desc_chain_link := p_desc_blk2;
      p_desc_blk1^.desc_chain_link := p_temp_desc_blk;
    IFEND;

  PROCEND insert_to_desc_chain;
?? EJECT, TITLE := 'FUNCTION smaller_than' ??

  FUNCTION smaller_than (str1,
        str2: sft$descriptive_data;
        size1,
        size2: 0 .. sfc$max_descriptive_data_size): boolean;

    VAR
      shorter_size,
      temp_index: 0 .. sfc$max_descriptive_data_size,
      str1_shorter,
      value_decided: boolean;

    value_decided := FALSE;
    IF size1 > size2 THEN
      shorter_size := size1;
      str1_shorter := TRUE;
    ELSE
      shorter_size := size2;
      str1_shorter := FALSE;
    IFEND;

  /compare_loop/
    FOR temp_index := 1 TO shorter_size DO
      IF str1 (temp_index) < str2 (temp_index) THEN
        smaller_than := TRUE;
        value_decided := TRUE;
        EXIT /compare_loop/;
      ELSE
        IF str1 (temp_index) > str2 (temp_index) THEN
          smaller_than := FALSE;
          value_decided := TRUE;
          EXIT /compare_loop/;
        IFEND;
      IFEND;
    FOREND /compare_loop/;

    IF (str1_shorter) AND (NOT value_decided) THEN
      smaller_than := TRUE;
    IFEND;
    IF (NOT str1_shorter) AND (NOT value_decided) THEN
      smaller_than := FALSE;
    IFEND;

  FUNCEND smaller_than;


?? EJECT, TITLE := 'PROCEDURE date_time_processor' ??
{  This procedure is called by SCL when it encounters a command parameter  }
{  of type time_value, date_value, or time_interval.  It translates the    }
{  text of the parameter into an integer with the data packed as indicated }
{  below.                                                                  }
{
{  This procedure can process both dates and times because they have       }
{  similar formats.  Both consist of one, two or three numbers, separated  }
{  by colons (time) or slashes (date).                                     }
{
{  Formats for the output integer:
{
{    date_value:     year*10000 + month*100 + day
{
{    time_value:     hours*10000 + minutes*100 + seconds
{
{    time_interval:  hours*3600 + minutes*60 + seconds                     }




  PROCEDURE date_time_processor (value_name: clt$application_value_name;
        keyword_values: ^array [1 .. * ] OF ost$name;
        text: string ( * );
    VAR value: clt$value;
    VAR local_status: ost$status);

    VAR
      current_date_time: ost$date_time,
      token: clt$token,
      dt1,
      dt2,
      dt3: integer;

    VAR
      error_code: ost$status_condition,
      expected_separator: char,
      index: ost$string_index;

    index := 1;

    value.kind := clc$integer_value;
    value.int.radix_specified := FALSE;

    { Remember what type of separator to expect, and what the error code
    { and defaults should be, depending on the type of parameter that we are }
    { processing. }

    IF value_name = 'TIME_VALUE                     ' THEN
      expected_separator := ':';
      error_code := pme$bad_time;
      dt2 := 0;
      dt3 := 0;
    ELSE
      IF value_name = 'DATE_VALUE                     ' THEN
        expected_separator := '/';
        error_code := pme$bad_date;
        dt2 := - 1;
        dt3 := - 1;
      ELSE
        expected_separator := ':';
        error_code := pme$bad_time;
        dt2 := - 1;
        dt3 := - 1;
      IFEND;
    IFEND;

    { Translate the first number. }

    clp$scan_token (text, index, token, local_status);
    IF NOT local_status.normal THEN
      RETURN;
    IFEND;
    IF token.kind <> clc$integer_token THEN
      osp$set_status_abnormal (pmc$external_log_management_id, error_code, text, local_status);
      RETURN;
    IFEND;
    dt1 := token.int.value;

    { See if there is more to the parameter. }

    IF STRLENGTH (text) > index THEN
      IF text (index) <> expected_separator THEN
        osp$set_status_abnormal (pmc$external_log_management_id, error_code, text, local_status);
        RETURN;
      IFEND;
      index := index + 1;

      { translate the second number. }

      clp$scan_token (text, index, token, local_status);
      IF NOT local_status.normal THEN
        RETURN;
      IFEND;
      IF token.kind <> clc$integer_token THEN
        osp$set_status_abnormal (pmc$external_log_management_id, error_code, text, local_status);
        RETURN;
      IFEND;
      dt2 := token.int.value;

      { See if there is more to the parameter. }

      IF STRLENGTH (text) > index THEN
        IF text (index) <> expected_separator THEN
          osp$set_status_abnormal (pmc$external_log_management_id, error_code, text, local_status);
          RETURN;
        IFEND;
        index := index + 1;

        { translate the third number. }

        clp$scan_token (text, index, token, local_status);
        IF NOT local_status.normal THEN
          RETURN;
        IFEND;
        IF token.kind <> clc$integer_token THEN
          osp$set_status_abnormal (pmc$external_log_management_id, error_code, text, local_status);
          RETURN;
        IFEND;
        dt3 := token.int.value;

        { If there is more to the parameter, it must be an error. }

        IF STRLENGTH (text) > index THEN
          osp$set_status_abnormal (pmc$external_log_management_id, error_code, text, local_status);
          RETURN;
        IFEND;

      IFEND;
    IFEND;

    { Pack the numbers into a single integer, according to the type of
    { value being processed. }

    IF value_name = 'TIME_INTERVAL                  ' THEN
      value.int.value := dt1;
      IF dt2 > - 1 THEN
        value.int.value := (value.int.value * 60) + dt2;
        IF dt3 > - 1 THEN
          value.int.value := (value.int.value * 60) + dt3;
        IFEND;
      IFEND;
    IFEND;

    IF value_name = 'DATE_VALUE                     ' THEN
      pmp$get_compact_date_time (current_date_time, local_status);
      IF (dt2 = - 1) AND (dt3 = - 1) THEN
        dt2 := dt1;
        dt1 := current_date_time.month;
        dt3 := current_date_time.year;
      ELSE
        IF dt3 = - 1 THEN
          dt3 := current_date_time.year;
        IFEND;
      IFEND;
      value.int.value := dt3 * 10000 + dt1 * 100 + dt2;
    IFEND;

    IF value_name = 'TIME_VALUE                     ' THEN
      value.int.value := dt1 * 10000 + dt2 * 100 + dt3;
    IFEND;

  PROCEND date_time_processor;

?? EJECT, TITLE := 'PROCEDURE eval_time' ??

  PROCEDURE eval_time (parameter_time: integer;
    VAR date_time: ost$date_time);

    VAR
      temp_time: integer;

    temp_time := parameter_time;
    date_time.hour := temp_time DIV 10000;
    temp_time := temp_time MOD 10000;
    date_time.minute := temp_time DIV 100;
    date_time.second := temp_time MOD 100;

  PROCEND eval_time;

?? EJECT, TITLE := 'PROCEDURE eval_date' ??

  PROCEDURE eval_date (parameter_date: integer;
    VAR date_time: ost$date_time);

    VAR
      temp_date: integer;

    temp_date := parameter_date;
    date_time.year := temp_date DIV 10000;
    temp_date := temp_date MOD 10000;
    date_time.month := temp_date DIV 100;
    date_time.day := temp_date MOD 100;

  PROCEND eval_date;
?? EJECT, TITLE := 'FUNCTION time_in_seconds' ??

  FUNCTION time_in_seconds (time_value: ost$date_time): integer;

    time_in_seconds := (time_value.hour * 3600) + (time_value.minute * 60) + time_value.second;

  FUNCEND time_in_seconds;
?? EJECT, TITLE := 'FUNCTION date_in_days' ??

  FUNCTION date_in_days (date_value: ost$date_time): integer;

    VAR
      leap_year_cummulative_days: [STATIC, READ] array [0 .. 12] of 0 .. 366 := [0, 31, 60, 91, 121, 152, 182,
        213, 244, 274, 305, 335, 366],

      non_leap_year_cummulative_days: [STATIC, READ] array [0 .. 12] of 0 .. 366 := [0, 31, 59, 90, 120, 151,
        181, 212, 243, 273, 304, 334, 365];


    IF pmp$this_is_a_leap_year (date_value.year) THEN
      date_in_days := leap_year_cummulative_days [date_value.month - 1] + date_value.day;
    ELSE
      date_in_days := non_leap_year_cummulative_days [date_value.month - 1] + date_value.day;
    IFEND;

  FUNCEND date_in_days;


?? OLDTITLE, TITLE := 'Sub-command Processors', NEWTITLE := '  ' ??
?? EJECT, TITLE := 'PROCEDURE defg_subcommand' ??

  PROCEDURE defg_subcommand (subcommand_parameters: clt$parameter_list;
    VAR subcommand_status: ost$status);

    VAR
      initial_group_ctl_blk: [STATIC, READ] group_ctl_blk := [ * , { name } blank_name, { pred_task_group_name
        {} blank_name, { pred_job_group_name } NIL, { group_chain_link } FALSE, { stat_specified } * , {
          {stat_code } FALSE, { date_specified } FALSE, { time_specified } [0, 1, 1, 0, 0, 0, 0], { start_dt }
        [99, 12, 31, 23, 59, 59, 999], { end_dt } NIL, { p_task_succ_group_list } NIL, {
          {p_job_succ_group_list } FALSE, { desc_specified } * , { desc_data_size } * , { desc_data } TRUE, {
          {between_active } NIL, { p_metric_list } FALSE, { copy_requested } [ * , * ], { copy_file_identifier
          {} NIL, { p_pred_task_head } NIL, { p_pred_job_head } FALSE, { desc_needed } NIL { p_desc_blk } ];

?? RIGHT := 110 ??
{  PDT defg_pdt (
{    group,g:  NAME = $REQUIRED
{    statistic, s:  NAME
{    time, t:  RANGE OF time_value date_time_processor
{    date, d:  RANGE OF date_value date_time_processor
{    job_predecessor, jp: NAME
{    task_predecessor, tp:  NAME
{    descriptive_data, dd:  STRING
{    between, b:  LIST 2 OF NAME
{      )

?? PUSH (LISTEXT := ON) ??

    VAR
      defg_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^defg_pdt_names, ^defg_pdt_params];

    VAR
      defg_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 16] of
        clt$parameter_name_descriptor := [['GROUP', 1], ['G', 1], ['STATISTIC', 2], ['S', 2], ['TIME', 3],
        ['T', 3], ['DATE', 4], ['D', 4], ['JOB_PREDECESSOR', 5], ['JP', 5], ['TASK_PREDECESSOR', 6],
        ['TP', 6], ['DESCRIPTIVE_DATA', 7], ['DD', 7], ['BETWEEN', 8], ['B', 8]];

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

{ GROUP G }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ STATISTIC S }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ TIME T }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_allowed, [NIL, clc$application_value, 'TIME_VALUE',
        [clc$linked_av_scanner, ^date_time_processor]]],

{ DATE D }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_allowed, [NIL, clc$application_value, 'DATE_VALUE',
        [clc$linked_av_scanner, ^date_time_processor]]],

{ JOB_PREDECESSOR JP }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ TASK_PREDECESSOR TP }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ DESCRIPTIVE_DATA DD }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$string_value, 0,
        osc$max_string_size]],

{ BETWEEN B }
      [[clc$optional], 2, 2, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]]];

?? POP ??

    VAR
      parameter_value: clt$value,
      p_group_ctl_blk: ^group_ctl_blk,
      parameter_specified: boolean,
      range_specified: boolean,
      str: ost$string,
      integer_value: clt$integer;

    clp$scan_parameter_list (subcommand_parameters, defg_pdt, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

    clp$get_value ('GROUP', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

    str.value := parameter_value.name.value;
    str.size := parameter_value.name.size;

    p_group_ctl_blk := NIL;
    find_group (str.value (1, max_name_size), p_group_ctl_blk);
    IF p_group_ctl_blk <> NIL THEN
      osp$set_status_abnormal (pmc$external_log_management_id, pme$redefined_group, str.value (1, str.size),
            subcommand_status);
      RETURN;
    IFEND;

    { Set up a new control block for this group. }

    ALLOCATE p_group_ctl_blk;
    p_group_ctl_blk^ := initial_group_ctl_blk;

    { Put the group name into the control block. }

    p_group_ctl_blk^.name := str.value (1, max_name_size);

    { Process the STATISTIC parameter. }

    clp$get_value ('STATISTIC', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

    IF parameter_value.kind <> clc$unknown_value THEN
      p_group_ctl_blk^.stat_specified := TRUE;
      str.value := parameter_value.name.value;
      str.size := parameter_value.name.size;

      IF NOT (str.value (1) IN alpha_chars) OR NOT (str.value (2) IN alpha_chars) THEN
        osp$set_status_abnormal (pmc$external_log_management_id, pme$bad_statistic, str.value (1, str.size),
              subcommand_status);
        RETURN;
      IFEND;

      clp$convert_string_to_integer (str.value (3, str.size - 2), integer_value, subcommand_status);
      IF NOT subcommand_status.normal THEN
        osp$set_status_abnormal (pmc$external_log_management_id, pme$bad_statistic, str.value (1, str.size),
              subcommand_status);
        RETURN;
      IFEND;

      IF integer_value.value > osc$max_status_condition_number THEN
        osp$set_status_abnormal (pmc$external_log_management_id, pme$bad_statistic, str.value (1, str.size),
              subcommand_status);
        RETURN;
      ELSE
        p_group_ctl_blk^.stat_code := osp$status_condition_code (str.value (1,2), integer_value.value);
      IFEND;
    IFEND;

    { Process the TIME parameter }

    clp$get_value ('TIME', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    IF parameter_value.kind <> clc$unknown_value THEN
      p_group_ctl_blk^.time_specified := TRUE;
      eval_time (parameter_value.int.value, p_group_ctl_blk^.start_dt);
      clp$test_range ('TIME', 1, 1, range_specified, subcommand_status);
      IF NOT subcommand_status.normal THEN
        RETURN;
      IFEND;
      IF range_specified THEN
        clp$get_value ('TIME', 1, 1, clc$high, parameter_value, subcommand_status);
        IF NOT subcommand_status.normal THEN
          RETURN;
        IFEND;
        eval_time (parameter_value.int.value, p_group_ctl_blk^.end_dt);
      ELSE
        p_group_ctl_blk^.end_dt.hour := p_group_ctl_blk^.start_dt.hour;
        p_group_ctl_blk^.end_dt.minute := p_group_ctl_blk^.start_dt.minute;
        p_group_ctl_blk^.end_dt.second := p_group_ctl_blk^.start_dt.second;
      IFEND;
    IFEND;

    { Process the DATE parameter }

    clp$get_value ('DATE', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    IF parameter_value.kind <> clc$unknown_value THEN
      p_group_ctl_blk^.date_specified := TRUE;
      eval_date (parameter_value.int.value, p_group_ctl_blk^.start_dt);
      clp$test_range ('DATE', 1, 1, range_specified, subcommand_status);
      IF NOT subcommand_status.normal THEN
        RETURN;
      IFEND;
      IF range_specified THEN
        clp$get_value ('DATE', 1, 1, clc$high, parameter_value, subcommand_status);
        IF NOT subcommand_status.normal THEN
          RETURN;
        IFEND;
        eval_date (parameter_value.int.value, p_group_ctl_blk^.end_dt);
      ELSE
        p_group_ctl_blk^.end_dt.year := p_group_ctl_blk^.start_dt.year;
        p_group_ctl_blk^.end_dt.month := p_group_ctl_blk^.start_dt.month;
        p_group_ctl_blk^.end_dt.day := p_group_ctl_blk^.start_dt.day;
      IFEND;
    IFEND;

    { Process the descriptive_data command. }

    clp$get_value ('DESCRIPTIVE_DATA', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    IF parameter_value.kind <> clc$unknown_value THEN
      str := parameter_value.str;
      IF str.size = 0 THEN
        osp$set_status_abnormal (pmc$external_log_management_id, pme$null_desc_data, '', subcommand_status);
        RETURN;
      IFEND;
      p_group_ctl_blk^.desc_specified := TRUE;
      p_group_ctl_blk^.desc_data := str.value (1, str.size);
      p_group_ctl_blk^.desc_data_size := str.size;
    IFEND;

    { Process the task_predecessor parameter. }

    clp$get_value ('TASK_PREDECESSOR', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    IF parameter_value.kind <> clc$unknown_value THEN
      p_group_ctl_blk^.pred_task_group_name := parameter_value.name.value;
    IFEND;

    { Process the job_predecessor parameter. }

    clp$get_value ('JOB_PREDECESSOR', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    IF parameter_value.kind <> clc$unknown_value THEN
      p_group_ctl_blk^.pred_job_group_name := parameter_value.name.value;
    IFEND;

    p_group_ctl_blk^.group_chain_link := group_chain_head;
    group_chain_head := p_group_ctl_blk;

  PROCEND defg_subcommand;
?? EJECT, TITLE := 'PROCEDURE defm_subcommand' ??

  PROCEDURE defm_subcommand (subcommand_parameters: clt$parameter_list;
    VAR subcommand_status: ost$status);

{ PDT defm_pdt (
{   metric, m: NAME = $REQUIRED
{   group, g: NAME = $REQUIRED
{   scale_factor, sf: INTEGER
{   unit, u: STRING
{   counter, c: INTEGER 1..255
{   expression, e: STRING
{   incremental, i: BOOLEAN = FALSE
{   )

?? PUSH (LISTEXT := ON) ??

  VAR
    defm_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^defm_pdt_names, ^defm_pdt_params];

  VAR
    defm_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 14] of
      clt$parameter_name_descriptor := [['METRIC', 1], ['M', 1], ['GROUP', 2], ['G', 2], ['SCALE_FACTOR', 3],
      ['SF', 3], ['UNIT', 4], ['U', 4], ['COUNTER', 5], ['C', 5], ['EXPRESSION', 6], ['E', 6], ['INCREMENTAL'
      , 7], ['I', 7]];

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

{ METRIC M }
    [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ GROUP G }
    [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ SCALE_FACTOR SF }
    [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$integer_value, -9223372036854775806,
      9223372036854775807]],

{ UNIT U }
    [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$string_value, 0, osc$max_string_size
      ]],

{ COUNTER C }
    [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$integer_value, 1, 255]],

{ EXPRESSION E }
    [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$string_value, 0, osc$max_string_size
      ]],

{ INCREMENTAL I }
    [[clc$optional_with_default, ^defm_pdt_dv7], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL,
      clc$boolean_value]]];

  VAR
    defm_pdt_dv7: [STATIC, READ, cls$pdt_names_and_defaults] string (5) := 'FALSE';

?? POP ??

    VAR
      parameter_value: clt$value,
      parameter_specified: boolean,
      str: ost$string,
      p_group_ctl_blk: ^group_ctl_blk,
      p_metric_ctl_blk: ^metric_ctl_blk,
      p_metric_list: ^metric_list,
      p_old_metric_list: ^metric_list;


    clp$scan_parameter_list (subcommand_parameters, defm_pdt, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

    { set up the metric control block. }

    clp$get_value ('METRIC', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

    str.value := parameter_value.name.value;
    str.size := parameter_value.name.size;
    p_metric_ctl_blk := NIL;
    find_metric (str.value (1, max_name_size), p_metric_ctl_blk);

    IF p_metric_ctl_blk <> NIL THEN
      osp$set_status_abnormal (pmc$external_log_management_id, pme$redefined_metric, str.value (1, str.size),
            subcommand_status);
      RETURN;
    IFEND;

    ALLOCATE p_metric_ctl_blk;

    { Initialize the contents of the metric control block. }

    p_metric_ctl_blk^.name := str.value (1, max_name_size);
    p_metric_ctl_blk^.metric_type := undefined_metric;
    p_metric_ctl_blk^.time_stamp_needed := FALSE;
    p_metric_ctl_blk^.p_report_ctl_blk := NIL;

    clp$get_value ('GROUP', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    p_metric_ctl_blk^.group_name := parameter_value.name.value;

    { Process the SCALE_FACTOR parameter. }

    clp$get_value ('SCALE_FACTOR', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    IF parameter_value.kind <> clc$unknown_value THEN
      p_metric_ctl_blk^.scale_factor := parameter_value.int.value;
    ELSE
      p_metric_ctl_blk^.scale_factor := 1;
    IFEND;

    { Process the UNIT parameter. }

    clp$get_value ('UNIT', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    IF parameter_value.kind <> clc$unknown_value THEN
      p_metric_ctl_blk^.unit := parameter_value.str.value;
    ELSE
      p_metric_ctl_blk^.unit := ' ';
    IFEND;

    { Process the COUNTER parameter. }

    clp$get_value ('COUNTER', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    IF parameter_value.kind <> clc$unknown_value THEN
      IF p_metric_ctl_blk^.metric_type <> undefined_metric THEN
        osp$set_status_abnormal (pmc$external_log_management_id, pme$too_many_metric_types, p_metric_ctl_blk^.
              name, subcommand_status);
        RETURN;
      ELSE
        p_metric_ctl_blk^.metric_type := counter_metric;
        p_metric_ctl_blk^.counter_number := parameter_value.int.value;
      IFEND;
    IFEND;

    { Process the EXPRESSION parameter. }

    clp$get_value ('EXPRESSION', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    IF parameter_value.kind <> clc$unknown_value THEN
      IF parameter_value.str.value (1) <> '1' THEN
        osp$set_status_abnormal (pmc$external_log_management_id, pme$bad_expression, str.value,
              subcommand_status);
        RETURN;
      IFEND;
      p_metric_ctl_blk^.metric_type := expression_metric;
    IFEND;

    { Process the INCREMENTAL parameter. }

    clp$get_value ('INCREMENTAL', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
       RETURN;
    IFEND;
    p_metric_ctl_blk^.incremental := parameter_value.bool.value;
    p_metric_ctl_blk^.first_element := TRUE;

    { Make sure that a metric type has been specified. }

    IF p_metric_ctl_blk^.metric_type = undefined_metric THEN
      osp$set_status_abnormal (pmc$external_log_management_id, pme$no_metric_type, p_metric_ctl_blk^.name,
            subcommand_status);
      RETURN;
    IFEND;

    p_metric_ctl_blk^.metric_chain_link := metric_chain_head;
    metric_chain_head := p_metric_ctl_blk;

  PROCEND defm_subcommand;
?? EJECT, TITLE := 'PROCEDURE diss_subcommand' ??

  PROCEDURE diss_subcommand (subcommand_parameters: clt$parameter_list;
    VAR subcommand_status: ost$status);

?? RIGHT := 110 ??
{ PDT diss_pdt (
{   metric, m: NAME = $REQUIRED
{   title, t: STRING
{   display_statistic, ds: LIST OF KEY NUM MEAN MIN MAX VARIANCE INTERVAL SUM ALL = ALL
{   interval_value, iv: INTEGER = 0
{   )

?? PUSH (LISTEXT := ON) ??

  VAR
    diss_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^diss_pdt_names, ^diss_pdt_params];

  VAR
    diss_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 8] of
      clt$parameter_name_descriptor := [['METRIC', 1], ['M', 1], ['TITLE', 2], ['T', 2], ['DISPLAY_STATISTIC'
      , 3], ['DS', 3], ['INTERVAL_VALUE', 4], ['IV', 4]];

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

{ METRIC M }
    [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ TITLE T }
    [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$string_value, 0, osc$max_string_size
      ]],

{ DISPLAY_STATISTIC DS }
    [[clc$optional_with_default, ^diss_pdt_dv3], 1, clc$max_value_sets,1, 1, clc$value_range_not_allowed, [^
      diss_pdt_kv3, clc$keyword_value]],

{ INTERVAL_VALUE IV }
    [[clc$optional_with_default, ^diss_pdt_dv4], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL,
      clc$integer_value, -9223372036854775806, 9223372036854775807]]];

  VAR
    diss_pdt_kv3: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 8] of ost$name := ['NUM','MEAN','MIN'
      ,'MAX','VARIANCE','INTERVAL','SUM','ALL'];

  VAR
    diss_pdt_dv3: [STATIC, READ, cls$pdt_names_and_defaults] string (3) := 'ALL';

  VAR
    diss_pdt_dv4: [STATIC, READ, cls$pdt_names_and_defaults] string (1) := '0';

?? POP ??

    VAR
      p_report_ctl_blk: ^report_ctl_blk,
      parameter_value: clt$value,
      display_count: 0 .. clc$max_value_sets,
      index: integer,
      str: ost$string,
      parameter_specified: boolean;

    clp$scan_parameter_list (subcommand_parameters, diss_pdt, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

    { Set up the report control block, but do not yet link it into the chain. }
    ALLOCATE p_report_ctl_blk;
    p_report_ctl_blk^.report_type := summary_report;

    clp$get_value ('METRIC', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    str.value := parameter_value.name.value;
    str.size := parameter_value.name.size;
    p_report_ctl_blk^.metric_name := str.value (1, max_name_size);

    { Process the TITLE parameter. }

    clp$get_value ('TITLE', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    IF parameter_value.kind <> clc$unknown_value THEN
      p_report_ctl_blk^.title := parameter_value.str;
    ELSE
      p_report_ctl_blk^.title := str;
    IFEND;

    { Process the DISPLAY_STATISTIC parameter. }

     p_report_ctl_blk^.num := FALSE;
     p_report_ctl_blk^.mean := FALSE;
     p_report_ctl_blk^.min := FALSE;
     p_report_ctl_blk^.max := FALSE;
     p_report_ctl_blk^.variance := FALSE;
     p_report_ctl_blk^.interval := FALSE;
     p_report_ctl_blk^.sum := FALSE;

     clp$get_set_count ('DISPLAY_STATISTIC', display_count, subcommand_status);
     IF NOT subcommand_status.normal THEN
        RETURN;
     IFEND;
     /display_loop/
        FOR index := 1 to display_count DO
            clp$get_value ('DISPLAY_STATISTIC', index, 1, clc$low, parameter_value,
                            subcommand_status);
            IF NOT subcommand_status.normal THEN
               RETURN;
            IFEND;
            IF parameter_value.name.value = 'ALL' THEN
               p_report_ctl_blk^.num := TRUE;
               p_report_ctl_blk^.mean := TRUE;
               p_report_ctl_blk^.min := TRUE;
               p_report_ctl_blk^.max := TRUE;
               p_report_ctl_blk^.variance := TRUE;
               p_report_ctl_blk^.interval := TRUE;
               p_report_ctl_blk^.sum := TRUE;
               EXIT /display_loop/
            ELSEIF parameter_value.name.value = 'NUM' THEN
               p_report_ctl_blk^.num := TRUE;
            ELSEIF parameter_value.name.value = 'MEAN' THEN
               p_report_ctl_blk^.mean := TRUE;
            ELSEIF parameter_value.name.value = 'MIN' THEN
               p_report_ctl_blk^.min := TRUE;
            ELSEIF parameter_value.name.value = 'MAX' THEN
               p_report_ctl_blk^.max := TRUE;
            ELSEIF parameter_value.name.value = 'VARIANCE' THEN
               p_report_ctl_blk^.variance := TRUE;
            ELSEIF parameter_value.name.value = 'INTERVAL' THEN
               p_report_ctl_blk^.interval := TRUE;
            ELSEIF parameter_value.name.value = 'SUM' THEN
               p_report_ctl_blk^.sum := TRUE;
          IFEND;
     FOREND /display_loop/;

    { Process the INTERVAL_VALUE parameter. }

    clp$get_value ('INTERVAL_VALUE', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
       RETURN;
    IFEND;
    p_report_ctl_blk^.interval_value := parameter_value.int.value;

    { link the report control block into the chain. }
    link_report (p_report_ctl_blk);

  PROCEND diss_subcommand;

?? EJECT, TITLE := 'PROCEDURE disd_subcommand' ??

  PROCEDURE disd_subcommand (subcommand_parameters: clt$parameter_list;
    VAR subcommand_status: ost$status);

{ PDT disd_pdt (
{   metric, m:  NAME = $REQUIRED
{   title, t:  STRING
{   limit, limits, l:  LIST 2, 2 OF INTEGER
{   display_option, do: KEY max_min_bound, first_max_centered,
{                         second_max_centered = max_min_bound
{   x_interval, xi: KEY self_adjust, large, medium, small = self_adjust
{   )


?? PUSH (LIST := OFF) ??

    VAR
      disd_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^disd_pdt_names, ^disd_pdt_params];

    VAR
      disd_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 11] of
        clt$parameter_name_descriptor := [['METRIC', 1], ['M', 1], ['TITLE', 2], ['T', 2], ['LIMIT', 3], [
        'LIMITS', 3], ['L', 3], ['DISPLAY_OPTION', 4], ['DO', 4], ['X_INTERVAL', 5], ['XI', 5]];

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

{ METRIC M }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ TITLE T }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$string_value, 0,
        osc$max_string_size]],

{ LIMIT LIMITS L }
      [[clc$optional], 1, 2, 2, 2, clc$value_range_not_allowed, [NIL, clc$integer_value, - 281474976710655,
        281474976710655]],

{ DISPLAY_OPTION  DO }
      [[clc$optional_with_default, ^disd_pdt_dv4], 1, 1, 1, 1, clc$value_range_not_allowed, [^disd_pdt_kv4,
        clc$keyword_value]],

{  X_INTERVAL  XI  }
      [[clc$optional_with_default, ^disd_pdt_dv5], 1, 1, 1, 1, clc$value_range_not_allowed, [^disd_pdt_kv5,
        clc$keyword_value]]];

    VAR
      disd_pdt_dv4: [STATIC, READ, cls$pdt_names_and_defaults] string (13) := 'MAX_MIN_BOUND';

    VAR
      disd_pdt_kv4: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 3] of ost$name := ['MAX_MIN_BOUND',
        'FIRST_MAX_CENTERED', 'SECOND_MAX_CENTERED'];

    VAR
      disd_pdt_dv5: [STATIC, READ, cls$pdt_names_and_defaults] string (11) := 'SELF_ADJUST';

    VAR
      disd_pdt_kv5: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 4] of ost$name := ['SELF_ADJUST',
        'LARGE', 'MEDIUM', 'SMALL'];

?? POP ??

    VAR
      do_keyword_array: [STATIC, READ] array [display_types] of string (19) := ['MAX_MIN_BOUND      ',
        'FIRST_MAX_CENTERED ', 'SECOND_MAX_CENTERED'];

    VAR
      xi_keyword_array: [STATIC, READ] array [interval_types] of string (11) := ['SELF_ADJUST', 'LARGE      ',
        'MEDIUM     ', 'SMALL      '];

    VAR
      msg_line: string (80),
      p_report_ctl_blk: ^report_ctl_blk,
      parameter_value: clt$value,
      str: ost$string,
      parameter_specified: boolean,
      display_index: display_types,
      interval_index: interval_types,
      set_count: 0 .. clc$max_value_sets;

    clp$scan_parameter_list (subcommand_parameters, disd_pdt, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

    { Set up the report control block, but do not yet link it into the chain. }
    ALLOCATE p_report_ctl_blk;
    p_report_ctl_blk^.report_type := distribution_report;

    clp$get_value ('METRIC', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    str.value := parameter_value.name.value;
    str.size := parameter_value.name.size;
    p_report_ctl_blk^.metric_name := str.value (1, max_name_size);

    { Process the TITLE parameter. }

    clp$get_value ('TITLE', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    IF parameter_value.kind <> clc$unknown_value THEN
      p_report_ctl_blk^.title := parameter_value.str;
    ELSE
      p_report_ctl_blk^.title := str;
    IFEND;

    { Process the LIMIT parameter. }

    p_report_ctl_blk^.x_low_limit := - 1;
    p_report_ctl_blk^.x_high_limit := - 1;
    p_report_ctl_blk^.cnt_low_limit := - 1;
    p_report_ctl_blk^.cnt_high_limit := - 1;

    clp$test_parameter ('LIMIT', parameter_specified, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    IF parameter_specified THEN
      clp$get_set_count ('LIMIT', set_count, subcommand_status);
      IF NOT subcommand_status.normal THEN
        RETURN;
      IFEND;
      IF set_count > 0 THEN
        clp$get_value ('LIMIT', 1, 1, clc$low, parameter_value, subcommand_status);
        IF NOT subcommand_status.normal THEN
          RETURN;
        IFEND;
        p_report_ctl_blk^.x_low_limit := parameter_value.int.value;
        clp$get_value ('LIMIT', 1, 2, clc$low, parameter_value, subcommand_status);
        IF NOT subcommand_status.normal THEN
          RETURN;
        IFEND;
        p_report_ctl_blk^.x_high_limit := parameter_value.int.value;
        IF set_count > 1 THEN
          clp$get_value ('LIMIT', 2, 1, clc$low, parameter_value, subcommand_status);
          IF NOT subcommand_status.normal THEN
            RETURN;
          IFEND;
          p_report_ctl_blk^.cnt_low_limit := parameter_value.int.value;
          clp$get_value ('LIMIT', 2, 2, clc$low, parameter_value, subcommand_status);
          IF NOT subcommand_status.normal THEN
            RETURN;
          IFEND;
          p_report_ctl_blk^.cnt_high_limit := parameter_value.int.value;
        IFEND;
      IFEND;
    IFEND;

    clp$get_value ('DISPLAY_OPTION', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

  /identify_display/
    FOR display_index := max_min_bound TO second_max_centered DO
      IF do_keyword_array [display_index] (1, parameter_value.name.size) = parameter_value.name.value (1,
            parameter_value.name.size) THEN
        p_report_ctl_blk^.display_option := display_index;
        EXIT /identify_display/;
      IFEND;
    FOREND /identify_display/;

    clp$get_value ('X_INTERVAL', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

  /identify_interval/
    FOR interval_index := self_adjust TO small DO
      IF xi_keyword_array [interval_index] (1, parameter_value.name.size) = parameter_value.name.value (1,
            parameter_value.name.size) THEN
        p_report_ctl_blk^.x_interval := interval_index;
        EXIT /identify_interval/;
      IFEND;
    FOREND /identify_interval/;

    { link the report control block into the chain. }
    link_report (p_report_ctl_blk);

  PROCEND disd_subcommand;
?? EJECT, TITLE := 'PROCEDURE disls_subcommand' ??

  PROCEDURE disls_subcommand (subcommand_parameters: clt$parameter_list;
    VAR subcommand_status: ost$status);

{ PDT disls_pdt (
{   output, o: FILE = $OUTPUT
{   )

?? PUSH (LISTEXT := ON) ??

  VAR
    disls_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^disls_pdt_names, ^disls_pdt_params
      ];

  VAR
    disls_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 2] of
      clt$parameter_name_descriptor := [['OUTPUT', 1], ['O', 1]];

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

{ OUTPUT O }
    [[clc$optional_with_default, ^disls_pdt_dv1], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL,
      clc$file_value]]];

  VAR
    disls_pdt_dv1: [STATIC, READ, cls$pdt_names_and_defaults] string (7) := '$OUTPUT';

?? POP ??

    VAR
      parameter_value: clt$value,
      saved: amt$file_identifier,
      output_access_array: [STATIC, READ] array [1..1] of amt$access_selection := [[amc$file_contents,
        amc$list]];

      clp$scan_parameter_list (subcommand_parameters, disls_pdt, subcommand_status);
      IF NOT subcommand_status.normal THEN
         RETURN;
      IFEND;

      {process the output parameter}
      clp$get_value ('OUTPUT', 1, 1, clc$low, parameter_value, subcommand_status);
      IF NOT subcommand_status.normal THEN
         RETURN;
      IFEND;

      p_log_blk := log_chain_head;
      saved := output_file;

      {open the output file}
      amp$open (parameter_value.file.local_file_name, amc$record, ^output_access_array, output_file,
                subcommand_status);
         check_status (subcommand_status);

      {open the input file}
      amp$open (p_log_blk^.log_file_name, amc$record, p_access_array, input_file, subcommand_status);
         check_status (subcommand_status);

      emit_statistics_report;

      amp$close (output_file, subcommand_status);
         check_status (subcommand_status);
      output_file := saved;
      amp$close (input_file, subcommand_status);
         check_status (subcommand_status);

  PROCEND  disls_subcommand;
?? EJECT, TITLE := 'PROCEDURE distd_subcommand' ??

  PROCEDURE distd_subcommand (subcommand_parameters: clt$parameter_list;
    VAR subcommand_status: ost$status);


?? RIGHT := 110 ??
{
{ pdt distd_pdt(
{   metric, m: name = $required
{   metric_limits, ml: list 2..2 of integer  = $required
{   title, t: string)

?? PUSH (LISTEXT := ON) ??

    VAR
      distd_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^distd_pdt_names,
        ^distd_pdt_params];

    VAR
      distd_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 6] of
        clt$parameter_name_descriptor := [['METRIC', 1], ['M', 1], ['METRIC_LIMITS', 2], ['ML', 2], ['TITLE',
        3], ['T', 3]];

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

{ METRIC M }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ METRIC_LIMITS ML }
      [[clc$required], 2, 2, 1, 1, clc$value_range_not_allowed, [NIL, clc$integer_value, - 281474976710655,
        281474976710655]],

{ TITLE T }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$string_value, 0,
        osc$max_string_size]]];

?? POP ??

    VAR
      p_report_ctl_blk: ^report_ctl_blk,
      parameter_value: clt$value,
      str: ost$string;


    clp$scan_parameter_list (subcommand_parameters, distd_pdt, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

    ALLOCATE p_report_ctl_blk;
    p_report_ctl_blk^.report_type := time_distribution_report;

    clp$get_value ('METRIC', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

    str.value := parameter_value.name.value;
    str.size := parameter_value.name.size;
    p_report_ctl_blk^.metric_name := str.value;


    clp$get_value ('TITLE', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

    IF parameter_value.kind <> clc$unknown_value THEN
      p_report_ctl_blk^.title := parameter_value.str;
    ELSE
      p_report_ctl_blk^.title := str;
    IFEND;

    clp$get_value ('METRIC_LIMITS', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

    p_report_ctl_blk^.metric_low_limit := parameter_value.int.value;

    clp$get_value ('METRIC_LIMITS', 2, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

    p_report_ctl_blk^.metric_high_limit := parameter_value.int.value;

    IF p_report_ctl_blk^.metric_high_limit < p_report_ctl_blk^.metric_low_limit THEN
      osp$set_status_abnormal (pmc$external_log_management_id, pme$bad_high_low_limit,
        'METRIC HIGH/LOW LIMITS ARE INCORRECT', subcommand_status);
      RETURN;
    IFEND;

    link_report (p_report_ctl_blk);

  PROCEND distd_subcommand;

?? EJECT, TITLE := 'PROCEDURE disdd_subcommand' ??

  PROCEDURE disdd_subcommand (subcommand_parameters: clt$parameter_list;
    VAR subcommand_status: ost$status);


{ PDT disdd_pdt (
{   group, g: NAME = $REQUIRED
{   title, t: STRING
{   )

?? PUSH (LISTEXT := ON) ??

    VAR
      disdd_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^disdd_pdt_names,
        ^disdd_pdt_params];

    VAR
      disdd_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 4] of
        clt$parameter_name_descriptor := [['GROUP', 1], ['G', 1], ['TITLE', 2], ['T', 2]];

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

{ GROUP G }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ TITLE T }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$string_value, 0,
        osc$max_string_size]]];

?? POP ??

    VAR
      parameter_value: clt$value,
      parameter_specified: boolean,
      str: ost$string,
      p_report_ctl_blk: ^report_ctl_blk;

    clp$scan_parameter_list (subcommand_parameters, disdd_pdt, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

{  Set up the report control block, but do not link it into the chain yet.  }

    ALLOCATE p_report_ctl_blk;
    p_report_ctl_blk^.report_type := datades_report;

{  Process the GROUP parameter  }
    clp$get_value ('GROUP', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    str.value := parameter_value.name.value;
    str.size := parameter_value.name.size;
    p_report_ctl_blk^.group_name := str.value (1, str.size);

{  Process the TITLE parameter  }

    clp$get_value ('TITLE', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    IF parameter_value.kind <> clc$unknown_value THEN
      p_report_ctl_blk^.title := parameter_value.str;
    ELSE
      p_report_ctl_blk^.title := str;
    IFEND;

    link_report (p_report_ctl_blk);

  PROCEND disdd_subcommand;

?? EJECT, TITLE := 'PROCEDURE dumg_subcommand' ??

  PROCEDURE dumg_subcommand (subcommand_parameters: clt$parameter_list;
    VAR subcommand_status: ost$status);

?? RIGHT := 110 ??
{ PDT dumg_pdt (
{   group, g:  NAME = $REQUIRED
{   counter_format, cf: list 1..255, 1..2 range of integer 1..255
{   title, t:  STRING
{     )

?? PUSH (LISTEXT := ON) ??

    VAR
      dumg_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^dumg_pdt_names, ^dumg_pdt_params];

    VAR
      dumg_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 6] of
        clt$parameter_name_descriptor := [['GROUP', 1], ['G', 1], ['COUNTER_FORMAT', 2], ['CF', 2], ['TITLE',
        3], ['T', 3]];

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

{ GROUP G }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ COUNTER_FORMAT CF }
      [[clc$optional], 1, 255, 1, 2, clc$value_range_allowed, [NIL, clc$integer_value, 1, 255]],

{ TITLE T }
      [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$string_value, 0,
        osc$max_string_size]]];

?? POP ??

    CONST
      default_radix = 10;

    VAR
      high_counter_value: 1 .. sfc$max_number_of_counters,
      i: 0 .. sfc$max_number_of_counters,
      j: 0 .. sfc$max_number_of_counters,
      low_counter_value: 1 .. sfc$max_number_of_counters,
      p_report_ctl_blk: ^report_ctl_blk,
      parameter_value: clt$value,
      parameter_specified: boolean,
      radix: 8 .. 16,
      set_count: 0 .. clc$max_value_sets,
      str: ost$string;

    clp$scan_parameter_list (subcommand_parameters, dumg_pdt, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

    { Set up the report control block, but do not yet link it
    { into the report chain. }

    ALLOCATE p_report_ctl_blk;
    p_report_ctl_blk^.report_type := dump_report;

    { Process the GROUP parameter. }

    clp$get_value ('GROUP', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    str.value := parameter_value.name.value;
    str.size := parameter_value.name.size;
    p_report_ctl_blk^.group_name := str.value (1, str.size);

    { Process the COUNTER_FORMAT parameter}

    FOR i := 1 TO sfc$max_number_of_counters DO
      p_report_ctl_blk^.counter_radix [i] := default_radix;
    FOREND;

    clp$get_set_count ('COUNTER_FORMAT', set_count, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

    FOR i := 1 TO set_count DO
      clp$get_value ('COUNTER_FORMAT', i, 1, clc$low, parameter_value, subcommand_status);
      IF NOT subcommand_status.normal THEN
        RETURN;
      IFEND;
      low_counter_value := parameter_value.int.value;

      clp$get_value ('COUNTER_FORMAT', i, 1, clc$high, parameter_value, subcommand_status);
      IF NOT subcommand_status.normal THEN
        RETURN;
      IFEND;
      high_counter_value := parameter_value.int.value;

      clp$get_value ('COUNTER_FORMAT', i, 2, clc$low, parameter_value, subcommand_status);
      IF NOT subcommand_status.normal THEN
        RETURN;
      IFEND;
      CASE parameter_value.int.value OF
      = 8, 10, 16 =
        radix := parameter_value.int.value;
      ELSE
        osp$set_status_abnormal ('CL', cle$integer_out_of_range, '', subcommand_status);
        osp$append_status_integer (osc$status_parameter_delimiter, parameter_value.int.value, parameter_value.
              int.radix, parameter_value.int.radix_specified, subcommand_status);
        osp$append_status_parameter (osc$status_parameter_delimiter, ' for COUNTER_FORMAT radix',
              subcommand_status);
        RETURN;
      CASEND;

      FOR j := low_counter_value TO high_counter_value DO
        p_report_ctl_blk^.counter_radix [j] := radix;
      FOREND;

    FOREND;

    { Process the TITLE parameter. }

    clp$get_value ('TITLE', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    IF parameter_value.kind <> clc$unknown_value THEN
      p_report_ctl_blk^.title := parameter_value.str;
    ELSE
      p_report_ctl_blk^.title := str;
    IFEND;


    link_report (p_report_ctl_blk);

  PROCEND dumg_subcommand;
?? EJECT, TITLE := 'PROCEDURE gengf_subcommand' ??

  PROCEDURE gengf_subcommand (subcommand_parameters: clt$parameter_list;
    VAR subcommand_status: ost$status);

{ PDT gengf_pdt (
{   group, g: NAME = $REQUIRED
{   output, o: FILE = $OUTPUT
{     )

?? PUSH (LISTEXT := ON) ??

    VAR
      gengf_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^gengf_pdt_names,
        ^gengf_pdt_params];

    VAR
      gengf_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 4] of
        clt$parameter_name_descriptor := [['GROUP', 1], ['G', 1], ['OUTPUT', 2], ['O', 2]];

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

{ GROUP G }
      [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 1, osc$max_name_size]],

{ OUTPUT O }
      [[clc$optional_with_default, ^gengf_pdt_dv2], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL,
        clc$file_value]]];

    VAR
      gengf_pdt_dv2: [STATIC, READ, cls$pdt_names_and_defaults] string (7) := '$OUTPUT';

?? POP ??

    VAR
      p_report_ctl_blk: ^report_ctl_blk,
      parameter_value: clt$value,
      parameter_specified: boolean,
      str: ost$string;

    clp$scan_parameter_list (subcommand_parameters, gengf_pdt, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;

{  Set up the report control block, but do not yet link it
{  into the report chain.

    ALLOCATE p_report_ctl_blk;
    p_report_ctl_blk^.report_type := gen_group_file;

{  Process the GROUP parameter.  }

    clp$get_value ('GROUP', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    p_report_ctl_blk^.group_name := parameter_value.name.value;

{  Process the OUTPUT parameter.  }

    clp$get_value ('OUTPUT', 1, 1, clc$low, parameter_value, subcommand_status);
    IF NOT subcommand_status.normal THEN
      RETURN;
    IFEND;
    p_report_ctl_blk^.file_name := parameter_value.file.local_file_name;

{  Process the PERMANENT parameter.  }
{  This parameter has been deleted and the value is now set to FALSE.  }

    p_report_ctl_blk^.permanent := FALSE;

    IF (p_report_ctl_blk^.permanent) AND (p_report_ctl_blk^.file_name = default_output) THEN
{  FREE p_report_ctl_blk;
      osp$set_status_abnormal (pmc$external_log_management_id, pme$output_permanent,
        ' $OUTPUT SHOULD NOT BE A PERMANENT FILE.', subcommand_status);
      RETURN;
    IFEND;

    IF (p_report_ctl_blk^.permanent) AND (local_name_conflict (p_report_ctl_blk^.file_name)) THEN
      FREE p_report_ctl_blk;
      osp$set_status_abnormal (pmc$external_log_management_id, pme$local_name_conflict,
        ' WHEN PARAMETER P=TRUE, PARAMETER O SHOULD NOT BE REDEFINED', subcommand_status);
      RETURN;
    IFEND;

    link_report (p_report_ctl_blk);

  PROCEND gengf_subcommand;
?? EJECT, TITLE := 'PROCEDURE qui_subcommand' ??

  PROCEDURE qui_subcommand (subcommand_parameters: clt$parameter_list;
    VAR status: ost$status);

{ PDT quit_pdt (
{   STATUS)

?? PUSH (LISTEXT := ON) ??

  VAR
    quit_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^quit_pdt_names, ^quit_pdt_params];

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

  VAR
    quit_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 ??


    clp$scan_parameter_list (subcommand_parameters, quit_pdt, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clp$end_scan_command_file ('DISPLAY_BINARY_LOG             ', status);

  PROCEND qui_subcommand;

MODEND lgm$display_binary_log;
