?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Logging: Logging Interfaces' ??
MODULE lgm$logging_interfaces;

{ PURPOSE:
{   This module contains the gated interfaces used to access the local and global logs.

?? NEWTITLE := 'Global Declarations Referenced by This Module.', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc bat$record_header_type
*copyc clt$path_display_chunks
*copyc fsc$local
*copyc jmc$system_family
*copyc lgc$logging_statistics
*copyc lge$corrupted_log
*copyc lge$corrupted_statistic
*copyc lge$end_of_log
*copyc lge$incorrect_log_ordinal
*copyc lge$statistic_buffer_required
*copyc lge$unknown_log_file_identifier
*copyc lgt$display_option_selection
*copyc lgt$open_log_file_descriptor
*copyc ofe$error_codes
*copyc oss$task_shared
*copyc ost$caller_identifier
*copyc pmt$os_name
*copyc pmt$system_log_entry
*copyc sfc$statistic_version
*copyc sft$statistic_buffer
*copyc sft$statistic_header
*copyc sft$descriptive_data
?? POP ??
*copyc amp$get_file_attributes
*copyc amp$get_segment_pointer
*copyc amp$put_next
*copyc avp$accounting_administrator
*copyc avp$configuration_administrator
*copyc avp$system_administrator
*copyc avp$system_displays
*copyc avp$system_operator
*copyc clp$build_standard_title
*copyc clp$close_display
*copyc clp$convert_integer_to_string
*copyc clp$evaluate_file_reference
*copyc clp$fetch_display_log_indices
*copyc clp$new_display_line
*copyc clp$new_display_page
*copyc clp$open_display_reference
*copyc clp$put_display
*copyc clp$put_partial_display
*copyc clp$reset_for_next_display_page
*copyc clp$right_justify_string
*copyc clp$store_display_log_indices
*copyc clp$trimmed_string_size
*copyc fsp$close_file
*copyc fsp$open_file
*copyc fsp$path_element
*copyc fsp$set_evaluated_file_abnormal
*copyc i#build_adaptable_seq_pointer
*copyc i#current_sequence_position
*copyc i#move
*copyc ifp$invoke_pause_utility
*copyc lgp$add_entry_global_binary_log
*copyc lgp$add_entry_to_critical_log
*copyc lgp$add_entry_to_system_log
*copyc lgp$get_critical_log_read_info
*copyc lgp$get_entry_from_global_log
*copyc lgp$get_entry_from_critical_log
*copyc lgp$get_entry_from_global_log
*copyc lgp$get_entry_from_local_log
*copyc lgp$get_global_log_read_info
*copyc lgp$get_local_log_read_info
*copyc lgp$release_critical_log_space
*copyc lgp$release_global_log_space
*copyc osp$append_status_file
*copyc osp$append_status_parameter
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc osp$establish_condition_handler
*copyc osp$force_access_violation
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc osp$set_status_from_condition
*copyc pmp$continue_to_cause
*copyc pmp$get_unique_name
*copyc pmp$get_date
*copyc pmp$get_executing_task_gtid
*copyc sfp$build_statistic
*copyc tmp$dispose_of_signals_flags
*copyc clv$nil_display_control
*copyc lgv$critical_log_ctl
*copyc lgv$global_log_ctl
*copyc lgv$critical_log_name
*copyc lgv$log_names
*copyc lgv$local_log_ctl
*copyc osv$task_shared_heap
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module.', EJECT ??

{ The following constant defines the number of log messages to be displayed/processed between calls to
{ TMP$DISPOSE_OF_SIGNALS_FLAGS (which allows handling of pause breaks and terminate breaks).

  CONST
    lgc$signal_flag_process_count = 32;

  VAR
    lgv$open_log_file_descriptor: [XDCL, oss$task_shared] ^lgt$open_log_file_descriptor := NIL;

?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] lgp$close_log_file', EJECT ??
*copyc lgh$close_log_file

  PROCEDURE [XDCL, #GATE] lgp$close_log_file
    (    log_file_identifier: lgt$log_file_identifier;
     VAR status: ost$status);

    VAR
      next_log_file_descriptor_p: ^lgt$open_log_file_descriptor,
      current_log_file_descriptor_p: ^lgt$open_log_file_descriptor,
      previous_log_file_descriptor_p: ^lgt$open_log_file_descriptor;

    status.normal := TRUE;

{ Find the open log file descriptor.

    current_log_file_descriptor_p := lgp$open_log_file_descriptor (log_file_identifier);
    IF current_log_file_descriptor_p = NIL THEN
      osp$set_status_abnormal ('LG', lge$unknown_log_file_identifier, log_file_identifier, status);
      RETURN;
    IFEND;

{ If this is not an active log, close the log file.

    IF NOT current_log_file_descriptor_p^.active_log THEN
      fsp$close_file (current_log_file_descriptor_p^.bam_file_identifier, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;

{ Remove the open log file descriptor.

    previous_log_file_descriptor_p := current_log_file_descriptor_p^.backward;
    next_log_file_descriptor_p := current_log_file_descriptor_p^.forward;
    IF previous_log_file_descriptor_p = NIL THEN
      lgv$open_log_file_descriptor := next_log_file_descriptor_p;
      IF lgv$open_log_file_descriptor <> NIL THEN
        lgv$open_log_file_descriptor^.backward := NIL;
      IFEND;
    ELSE
      previous_log_file_descriptor_p^.forward := next_log_file_descriptor_p;
      IF next_log_file_descriptor_p <> NIL THEN
        next_log_file_descriptor_p^.backward := previous_log_file_descriptor_p;
      IFEND;
    IFEND;
    FREE current_log_file_descriptor_p IN osv$task_shared_heap^;

  PROCEND lgp$close_log_file;
?? OLDTITLE ??
?? NEWTITLE := 'lgp$display_log', EJECT ??
*copyc lgh$display_log

  PROCEDURE [XDCL, #GATE] lgp$display_log
    (    display_log_kind: clt$display_log_kind;
         display_option_selection: lgt$display_option_selection;
         output: fst$file_reference;
     VAR status: ost$status);

*copy clv$display_variables

    VAR
      backspace_count: ost$segment_length,
      byte_address: amt$file_byte_address,
      caller_identifier: ost$caller_identifier,
      default_ring_attributes: amt$ring_attributes,
      display_line: ^string ( * ),
      log_entry_index: 1 .. lgc$maximum_log_entry_size + 1,
      display_line_size: lgt$log_entry_size,
      display_control: clt$display_control,
      ending_offset: amt$file_byte_address,
      ignore_status: ost$status,
      indentation_size: 0 .. 2,
      indices: clt$display_log_indices,
      log_cycle: lgt$log_cycle,
      log_data: ^SEQ ( * ),
      log_entries_displayed: integer,
      log_entry_p: ^string ( * ),
      log_entry_size: lgt$log_entry_size;

?? NEWTITLE := 'condition_handler', EJECT ??
{ PURPOSE:
{   This condition handler is used to handle interactive pause break and terminate break conditions.  It also
{   insures that the output file is closed in the event of an error.

    PROCEDURE condition_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        local_status: ost$status;

      IF condition.selector = ifc$interactive_condition THEN
        IF condition.interactive_condition = ifc$pause_break THEN
          ifp$invoke_pause_utility (local_status);
        ELSEIF condition.interactive_condition = ifc$terminate_break THEN
          osp$set_status_from_condition ('LG', condition, save_area, status, local_status);
          EXIT lgp$display_log;
        ELSE
          pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
        IFEND
      ELSEIF condition.selector = pmc$block_exit_processing THEN
        clp$close_display (display_control, local_status);
      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
      IFEND;

    PROCEND condition_handler;
?? OLDTITLE, EJECT ??
?? NEWTITLE := 'clp$new_page_procedure', EJECT ??
*copy clp$new_page_procedure
?? OLDTITLE ??
?? NEWTITLE := 'put_subtitle', EJECT ??

    PROCEDURE put_subtitle
      (    display_control: clt$display_control;
       VAR status: ost$status);

{ The display_log output has no subtitles, this is merely a dummy routine used to keep the module consistent
{ with those that do produce subtitles.

    PROCEND put_subtitle;
?? OLDTITLE, EJECT ??

    status.normal := TRUE;
    #CALLER_ID (caller_identifier);

{ If the request is to display the system or the critical window log, make sure the user has
{ the appropriate authority.

    IF ((display_log_kind = clc$display_system_log) OR
          (display_log_kind = clc$display_critical_window_log)) AND
          NOT (avp$system_operator () OR avp$system_displays ()) THEN
      osp$set_status_abnormal ('OF', ofe$sou_not_active, 'system_operation or system_displays', status);
      RETURN;
    IFEND;

{ Initialize the display control variable.

    display_control := clv$nil_display_control;
    #SPOIL (display_control);

    osp$establish_condition_handler (^condition_handler, TRUE);

  /display_log/
    BEGIN

{ Open the output file.

      default_ring_attributes.r1 := caller_identifier.ring;
      default_ring_attributes.r2 := caller_identifier.ring;
      default_ring_attributes.r3 := caller_identifier.ring;
      clp$open_display_reference (output, ^clp$new_page_procedure, fsc$list, default_ring_attributes,
            display_control, status);
      IF NOT status.normal THEN
        EXIT /display_log/;
      IFEND;
      clv$titles_built := FALSE;
      IF display_log_kind = clc$display_system_log THEN
        clv$command_name := 'display_system_log';
      ELSEIF display_log_kind = clc$display_critical_window_log THEN
        clv$command_name := 'display_critical_window_log';
      ELSE
        clv$command_name := 'display_log';
      IFEND;
      IF display_control.page_width < clc$narrow_page_width THEN
        display_control.page_width := clc$narrow_page_width;
      IFEND;

{ Allocate space to hold the copies of the log entries and to build the display output.

      PUSH log_entry_p: [lgc$maximum_log_entry_size];
      PUSH display_line: [display_control.page_width];

{ Initialize the log information needed to read the log.

      IF display_option_selection.display_options = lgc$count THEN
        backspace_count := display_option_selection.count;
      ELSE
        backspace_count := 0;
      IFEND;

      IF display_log_kind = clc$display_system_log THEN
        lgp$get_global_log_read_info (pmc$system_log, backspace_count, log_cycle, log_data, ending_offset,
              status);
      ELSEIF display_log_kind = clc$display_critical_window_log THEN
        lgp$get_critical_log_read_info (backspace_count, log_cycle,
              log_data, ending_offset, status);
      ELSE
        lgp$get_local_log_read_info (pmc$job_log, backspace_count, log_cycle, log_data, ending_offset,
              status);
      IFEND;
      IF NOT status.normal THEN
        EXIT /display_log/;
      IFEND;

      clp$fetch_display_log_indices (indices);

      IF display_option_selection.display_options = lgc$all THEN
        RESET log_data;
      ELSEIF display_option_selection.display_options = lgc$last THEN
        IF (indices [display_log_kind].last_display_log_entry = 0) OR
              (indices [display_log_kind].last_log_cycle <> log_cycle) THEN
          RESET log_data;
        ELSE
          i#build_adaptable_seq_pointer (#RING (log_data), #SEGMENT (log_data), #OFFSET (log_data),
                #SIZE (log_data^), indices [display_log_kind].last_display_log_entry, log_data);
        IFEND;
      IFEND;

{ Save the ending offset and log cycle.

      indices [display_log_kind].last_display_log_entry := ending_offset;
      indices [display_log_kind].last_log_cycle := log_cycle;
      clp$store_display_log_indices (indices);

{ Display the contents of the log.

      log_entries_displayed := 0;
      WHILE i#current_sequence_position (log_data) <= ending_offset DO

{ Periodically allow signals and flags to be processed.  This allows the user to interupt the display.

        IF (log_entries_displayed MOD lgc$signal_flag_process_count) = 0 THEN
          tmp$dispose_of_signals_flags (tmc$long_term_wait);
        IFEND;
        log_entries_displayed := log_entries_displayed + 1;

{ Get the log entry to be displayed.

        IF display_log_kind = clc$display_system_log THEN
          lgp$get_entry_from_global_log (pmc$system_log, log_cycle, log_data, log_entry_size,
                #SEQ (log_entry_p^) ^, status);
        ELSEIF display_log_kind = clc$display_critical_window_log THEN
          lgp$get_entry_from_critical_log (log_cycle, log_data, log_entry_size,
                #SEQ (log_entry_p^) ^, status);
        ELSE
          lgp$get_entry_from_local_log (pmc$job_log, log_cycle, log_data, log_entry_size,
                #SEQ (log_entry_p^) ^, status);
        IFEND;
        IF NOT status.normal THEN
          EXIT /display_log/;
        IFEND;

{ Display the log entry, wrapping to more than one line if necessary.

        log_entry_index := 1;
        indentation_size := 0;

        WHILE log_entry_index <= log_entry_size DO
          IF (log_entry_size - log_entry_index + 1) <= (display_control.page_width - indentation_size) THEN
            display_line_size := log_entry_size - log_entry_index + 1;
          ELSE
            display_line_size := display_control.page_width - indentation_size;
          IFEND;
          display_line^ (indentation_size + 1, display_line_size) :=
                log_entry_p^ (log_entry_index, display_line_size);
          clp$put_display (display_control, display_line^ (1, indentation_size + display_line_size), clc$trim,
                status);
          IF NOT status.normal THEN
            EXIT /display_log/;
          IFEND;
          log_entry_index := log_entry_index + display_line_size;
          indentation_size := 2;
          display_line^ (1, indentation_size) := '  ';
        WHILEND;
      WHILEND;
    END /display_log/;

{ Clear the end of log status or log cycles do not match error if necessary.

    IF NOT status.normal AND ((status.condition = lge$end_of_log) OR
          (status.condition = lge$log_cycles_do_not_match)) THEN
      status.normal := TRUE;
    IFEND;

    clp$close_display (display_control, ignore_status);
    osp$disestablish_cond_handler;

  PROCEND lgp$display_log;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] lgp$display_critical_log_attr', EJECT ??
{ PURPOSE:
{   Displays the information contained in the critical window log control descriptor.

  PROCEDURE [XDCL, #GATE] lgp$display_critical_log_attr
    (    output: fst$file_reference;
     VAR status: ost$status);

*copy clv$display_variables

    VAR
      caller_identifier: ost$caller_identifier,
      default_ring_attributes: amt$ring_attributes,
      display_line: string (osc$max_string_size),
      display_line_size: integer,
      display_control: clt$display_control,
      ignore_status: ost$status,
      log_control_descriptor_p: ^lgt$critical_log_control_desc;

?? NEWTITLE := 'condition_handler', EJECT ??
{ PURPOSE:
{   This condition handler is used to handle interactive pause break and terminate break conditions.  It also
{   insures that the output file is closed in the event of an error.

    PROCEDURE condition_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        local_status: ost$status;

      IF condition.selector = ifc$interactive_condition THEN
        IF condition.interactive_condition = ifc$pause_break THEN
          ifp$invoke_pause_utility (local_status);
        ELSEIF condition.interactive_condition = ifc$terminate_break THEN
          osp$set_status_from_condition ('LG', condition, save_area, status, local_status);
          EXIT lgp$display_critical_log_attr;
        ELSE
          pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
        IFEND
      ELSEIF condition.selector = pmc$block_exit_processing THEN
        clp$close_display (display_control, local_status);
      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
      IFEND;

    PROCEND condition_handler;
?? OLDTITLE, EJECT ??
?? NEWTITLE := 'clp$new_page_procedure', EJECT ??
*copy clp$new_page_procedure
?? OLDTITLE ??
?? NEWTITLE := 'put_subtitle', EJECT ??

    PROCEDURE put_subtitle
      (    display_control: clt$display_control;
       VAR status: ost$status);

{ The display_critical_log_attr output has no subtitles, this is merely a dummy routine used to keep the
{ module consistent with those that do produce subtitles.

    PROCEND put_subtitle;
?? OLDTITLE, EJECT ??
    status.normal := TRUE;
    #CALLER_ID (caller_identifier);

{ Make sure the caller has system operation or system displays capability.

    IF NOT (avp$system_operator () OR avp$system_displays ()) THEN
      osp$set_status_abnormal ('OF', ofe$sou_not_active, 'system_operation or system_displays', status);
      RETURN;
    IFEND;

{ Initialize the display control variable.

    display_control := clv$nil_display_control;
    #SPOIL (display_control);

    osp$establish_condition_handler (^condition_handler, TRUE);

  /display_attributes/
    BEGIN

{ Open the output file.

      default_ring_attributes.r1 := caller_identifier.ring;
      default_ring_attributes.r2 := caller_identifier.ring;
      default_ring_attributes.r3 := caller_identifier.ring;
      clp$open_display_reference (output, ^clp$new_page_procedure, fsc$list, default_ring_attributes,
            display_control, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;
      clv$titles_built := FALSE;
      clv$command_name := 'display_critical_log_attributes';
      IF display_control.page_width < clc$narrow_page_width THEN
        display_control.page_width := clc$narrow_page_width;
      IFEND;

{ Get a pointer to the critical window log control descriptor.

      log_control_descriptor_p := ^lgv$critical_log_ctl;

{ Display the log name.

      STRINGREP (display_line, display_line_size, ' Log name: ',
            lgv$critical_log_name);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the log cycle.

      STRINGREP (display_line, display_line_size, ' Log cycle: ', log_control_descriptor_p^.log_cycle);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the log data PVA.

      STRINGREP (display_line, display_line_size, ' Log data PVA: ', log_control_descriptor_p^.log_data);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the log data size.

      STRINGREP (display_line, display_line_size, ' Log data size: ',
            #SIZE (log_control_descriptor_p^.log_data^));
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the log data position.

      STRINGREP (display_line, display_line_size, ' Log data position: ',
            i#current_sequence_position (log_control_descriptor_p^.log_data));
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the trailing log entry header pointer.

      STRINGREP (display_line, display_line_size, ' Trailing log entry header pointer: ',
            log_control_descriptor_p^.trailing_log_entry_header_p);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the maximum size.

      STRINGREP (display_line, display_line_size, ' Maximum size: ', log_control_descriptor_p^.maximum_size);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the preallocation size.

      STRINGREP (display_line, display_line_size, ' Preallocation size: ',
            log_control_descriptor_p^.preallocation_size);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the critical flag.

      STRINGREP (display_line, display_line_size, ' Critical: ', log_control_descriptor_p^.critical_log);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the lost message count.

      STRINGREP (display_line, display_line_size, ' Lost message count: ',
            log_control_descriptor_p^.lost_message_count);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display log full indicator.

      STRINGREP (display_line, display_line_size, ' Log full: ', log_control_descriptor_p^.log_full);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);

    END /display_attributes/;

    clp$close_display (display_control, ignore_status);
    osp$disestablish_cond_handler;

  PROCEND lgp$display_critical_log_attr;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] lgp$display_log_attributes', EJECT ??
{ PURPOSE:
{   Displays the information contained in the log control descriptor.

  PROCEDURE [XDCL, #GATE] lgp$display_log_attributes
    (    log: pmt$logs;
         output: fst$file_reference;
     VAR status: ost$status);

*copy clv$display_variables

    VAR
      caller_identifier: ost$caller_identifier,
      default_ring_attributes: amt$ring_attributes,
      display_line: string (osc$max_string_size),
      display_line_size: integer,
      display_control: clt$display_control,
      global_log: pmt$global_logs,
      ignore_status: ost$status,
      log_control_descriptor_p: ^lgt$log_control_descriptor;

?? NEWTITLE := 'condition_handler', EJECT ??
{ PURPOSE:
{   This condition handler is used to handle interactive pause break and terminate break conditions.  It also
{   insures that the output file is closed in the event of an error.

    PROCEDURE condition_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        local_status: ost$status;

      IF condition.selector = ifc$interactive_condition THEN
        IF condition.interactive_condition = ifc$pause_break THEN
          ifp$invoke_pause_utility (local_status);
        ELSEIF condition.interactive_condition = ifc$terminate_break THEN
          osp$set_status_from_condition ('LG', condition, save_area, status, local_status);
          EXIT lgp$display_log_attributes;
        ELSE
          pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
        IFEND
      ELSEIF condition.selector = pmc$block_exit_processing THEN
        clp$close_display (display_control, local_status);
      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
      IFEND;

    PROCEND condition_handler;
?? OLDTITLE, EJECT ??
?? NEWTITLE := 'clp$new_page_procedure', EJECT ??
*copy clp$new_page_procedure
?? OLDTITLE ??
?? NEWTITLE := 'put_subtitle', EJECT ??

    PROCEDURE put_subtitle
      (    display_control: clt$display_control;
       VAR status: ost$status);

{ The display_log_attributes output has no subtitles, this is merely a dummy routine used to keep the module
{ consistent with those that do produce subtitles.

    PROCEND put_subtitle;
?? OLDTITLE, EJECT ??
    status.normal := TRUE;
    #CALLER_ID (caller_identifier);

{ Make sure the caller has system operation or system displays capability.

    IF NOT (avp$system_operator () OR avp$system_displays ()) THEN
      osp$set_status_abnormal ('OF', ofe$sou_not_active, 'system_operation or system_displays', status);
      RETURN;
    IFEND;

{ Initialize the display control variable.

    display_control := clv$nil_display_control;
    #SPOIL (display_control);

    osp$establish_condition_handler (^condition_handler, TRUE);

  /display_attributes/
    BEGIN

{ Open the output file.

      default_ring_attributes.r1 := caller_identifier.ring;
      default_ring_attributes.r2 := caller_identifier.ring;
      default_ring_attributes.r3 := caller_identifier.ring;
      clp$open_display_reference (output, ^clp$new_page_procedure, fsc$list, default_ring_attributes,
            display_control, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;
      clv$titles_built := FALSE;
      clv$command_name := 'display_log_attributes';
      IF display_control.page_width < clc$narrow_page_width THEN
        display_control.page_width := clc$narrow_page_width;
      IFEND;

{ Get a pointer to the appropriate log control descriptor.

      IF log IN -$pmt$global_logset [] THEN
        global_log := log;
        log_control_descriptor_p := ^lgv$global_log_ctl [global_log];
      ELSE
        log_control_descriptor_p := lgv$local_log_ctl [log];
      IFEND;

{ Display the log name.

      STRINGREP (display_line, display_line_size, ' Log name: ',
            lgv$log_names [log_control_descriptor_p^.log]);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the log cycle.

      STRINGREP (display_line, display_line_size, ' Log cycle: ', log_control_descriptor_p^.log_cycle);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the log data PVA.

      STRINGREP (display_line, display_line_size, ' Log data PVA: ', log_control_descriptor_p^.log_data);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the log data size.

      STRINGREP (display_line, display_line_size, ' Log data size: ',
            #SIZE (log_control_descriptor_p^.log_data^));
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the log data position.

      STRINGREP (display_line, display_line_size, ' Log data position: ',
            i#current_sequence_position (log_control_descriptor_p^.log_data));
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the trailing log entry header pointer.

      STRINGREP (display_line, display_line_size, ' Trailing log entry header pointer: ',
            log_control_descriptor_p^.trailing_log_entry_header_p);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the maximum size.

      STRINGREP (display_line, display_line_size, ' Maximum size: ', log_control_descriptor_p^.maximum_size);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the preallocation size.

      STRINGREP (display_line, display_line_size, ' Preallocation size: ',
            log_control_descriptor_p^.preallocation_size);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the critical flag.

      STRINGREP (display_line, display_line_size, ' Critical: ', log_control_descriptor_p^.critical_log);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display the lost message count.

      STRINGREP (display_line, display_line_size, ' Lost message count: ',
            log_control_descriptor_p^.lost_message_count);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);
      IF NOT status.normal THEN
        EXIT /display_attributes/;
      IFEND;

{ Display log full indicator.

      STRINGREP (display_line, display_line_size, ' Log full: ', log_control_descriptor_p^.log_full);
      clp$put_display (display_control, display_line (1, display_line_size), clc$trim, status);

    END /display_attributes/;

    clp$close_display (display_control, ignore_status);
    osp$disestablish_cond_handler;

  PROCEND lgp$display_log_attributes;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] lgp$get_next_log_entry', EJECT ??
{ Retrieves the next log entry from a log.

  PROCEDURE [XDCL, #GATE] lgp$get_next_log_entry
    (    log_file_identifier: lgt$log_file_identifier;
         statistic_buffer_p: ^sft$statistic_buffer;
     VAR log_entry_p: ^lgt$log_entry;
     VAR status: ost$status);

    VAR
      bam_record_header_p: ^bat$record_header,
      caller_identifier: ost$caller_identifier,
      local_log_data: ^SEQ(*),
      log_entry_size: lgt$log_entry_size,
      open_log_file_descriptor_p: ^lgt$open_log_file_descriptor;

    status.normal := TRUE;
    #CALLER_ID (caller_identifier);

{ Find the open log file descriptor.

    open_log_file_descriptor_p := lgp$open_log_file_descriptor (log_file_identifier);
    IF open_log_file_descriptor_p = NIL THEN
      osp$set_status_abnormal ('LG', lge$unknown_log_file_identifier, log_file_identifier, status);
      RETURN;
    IFEND;

{ Make sure the caller has at least the same ring privilege as that used during the open request.

    IF caller_identifier.ring > open_log_file_descriptor_p^.open_ring THEN
      osp$force_access_violation;
    IFEND;

{ Get the next statistic from the log.

    IF open_log_file_descriptor_p^.active_log THEN
      IF statistic_buffer_p = NIL THEN
        osp$set_status_abnormal ('LG', lge$statistic_buffer_required, 'LGP$GET_NEXT_STATISTIC', status);
        RETURN;
      IFEND;
      log_entry_p := statistic_buffer_p;
      IF open_log_file_descriptor_p^.global_log THEN
        lgp$get_entry_from_global_log (open_log_file_descriptor_p^.log, open_log_file_descriptor_p^.log_cycle,
              open_log_file_descriptor_p^.log_data, log_entry_size, log_entry_p^, status);
      ELSE
        lgp$get_entry_from_local_log (open_log_file_descriptor_p^.log, open_log_file_descriptor_p^.log_cycle,
              open_log_file_descriptor_p^.log_data, log_entry_size, log_entry_p^, status);
      IFEND;
    ELSE

{ Make a copy of the log_data sequence pointer to use until the log entry has been retrieved.

      local_log_data := open_log_file_descriptor_p^.log_data;

{ Get the BAM record header.

      NEXT bam_record_header_p IN local_log_data;
      IF bam_record_header_p = NIL THEN
        osp$set_status_abnormal ('LG', lge$end_of_log, '', status);
        osp$append_status_file (osc$status_parameter_delimiter, open_log_file_descriptor_p^.file_reference,
              status);
        RETURN;
      IFEND;
      log_entry_size := bam_record_header_p^.length;

{ Get a pointer to the log entry.

      NEXT log_entry_p: [[REP log_entry_size OF cell]] IN local_log_data;
      IF log_entry_p = NIL THEN
        osp$set_status_abnormal ('LG', lge$end_of_log, '', status);
        osp$append_status_file (osc$status_parameter_delimiter, open_log_file_descriptor_p^.file_reference,
              status);
        RETURN;
      IFEND;

{ Update the log_data pointer in the open log file descriptor.

      open_log_file_descriptor_p^.log_data := local_log_data;

    IFEND;

  PROCEND lgp$get_next_log_entry;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] lgp$open_log_file', EJECT ??
*copyc lgh$open_log_file

  PROCEDURE [XDCL, #GATE] lgp$open_log_file
    (    log_file: fst$file_reference;
     VAR active_log: boolean;
     VAR log_file_identifier: lgt$log_file_identifier;
     VAR status: ost$status);

    VAR
      attachment_options: ^fst$attachment_options,
      caller_identifier: ost$caller_identifier,
      contains_data: boolean,
      ending_offset: amt$file_byte_address,
      evaluated_file_reference: fst$evaluated_file_reference,
      get_attributes: ^amt$get_attributes,
      file_exists: boolean,
      file_previously_opened: boolean,
      global_log: pmt$global_logs,
      log: pmt$logs,
      log_name: ost$name,
      new_open_log_file_descriptor_p: ^lgt$open_log_file_descriptor,
      segment_pointer: amt$segment_pointer,
      trailing_log_entry_header: lgt$log_entry_header;

    status.normal := TRUE;
    #CALLER_ID (caller_identifier);

{ Evaluate the file reference that was specified on the call.

    clp$evaluate_file_reference (log_file, $clt$file_ref_parsing_options [], TRUE, evaluated_file_reference,
          status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Determine if the specified log is one of the active logs.

    active_log := FALSE;
    IF (fsp$path_element (^evaluated_file_reference, 1) ^ = fsc$local) THEN
      log_name := fsp$path_element (^evaluated_file_reference, 2) ^;
    ELSEIF (fsp$path_element (^evaluated_file_reference, 1) ^ = jmc$system_family) AND
          (fsp$path_element (^evaluated_file_reference, 2) ^ = jmc$system_user) THEN
      log_name := fsp$path_element (^evaluated_file_reference, 3) ^;
    ELSE
      log_name := osc$null_name;
    IFEND;

    IF log_name <> osc$null_name THEN
    /check_for_active_log/
      FOR log := LOWERVALUE (log) TO UPPERVALUE (log) DO
        IF log_name = lgv$log_names [log] THEN
          active_log := TRUE;
          EXIT /check_for_active_log/;
        IFEND;
      FOREND /check_for_active_log/;
    IFEND;

{ If this is an active global log, make sure the user is allowed to access the log.

    IF active_log AND (log IN (-$pmt$global_logset [])) THEN
      global_log := log;
      verify_authority (caller_identifier, global_log, {critical_window_log = } FALSE, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;

{ Get a unique name to use as the log file identifier.

    pmp$get_unique_name (log_file_identifier, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Allocate an open log file descriptor and initialize it.

    ALLOCATE new_open_log_file_descriptor_p IN osv$task_shared_heap^;
    new_open_log_file_descriptor_p^.log_file_identifier := log_file_identifier;
    new_open_log_file_descriptor_p^.active_log := active_log;
    new_open_log_file_descriptor_p^.open_ring := caller_identifier.ring;

{ If this is an active log, get the necessary information from the log control descriptor.  Otherwise, open
{ the specified file for segment access.

    IF active_log THEN
      new_open_log_file_descriptor_p^.log := log;
      IF log IN (-$pmt$global_logset []) THEN
        new_open_log_file_descriptor_p^.global_log := TRUE;
        lgp$get_global_log_read_info (log, 0, new_open_log_file_descriptor_p^.log_cycle,
              new_open_log_file_descriptor_p^.log_data, ending_offset, status);
      ELSE
        new_open_log_file_descriptor_p^.global_log := FALSE;
        lgp$get_local_log_read_info (log, 0, new_open_log_file_descriptor_p^.log_cycle,
              new_open_log_file_descriptor_p^.log_data, ending_offset, status);
      IFEND;
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      RESET new_open_log_file_descriptor_p^.log_data;
    ELSE

{ Verify the ring privilege of the caller against the file attributes.

      PUSH get_attributes: [1 .. 1];
      get_attributes^ [1].key := amc$ring_attributes;
      amp$get_file_attributes (log_file, get_attributes^, file_exists, file_previously_opened, contains_data,
            status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      IF caller_identifier.ring > get_attributes^ [1].ring_attributes.r2 THEN
        fsp$set_evaluated_file_abnormal (evaluated_file_reference, ame$ring_validation_error, amc$open_req,
              '', status);
        RETURN;
      IFEND;

      PUSH attachment_options: [1 .. 6];
      attachment_options^ [1].selector := fsc$access_and_share_modes;
      attachment_options^ [1].access_modes.selector := fsc$specific_access_modes;
      attachment_options^ [1].access_modes.value := $fst$file_access_options [fsc$read];
      attachment_options^ [1].share_modes.selector := fsc$determine_from_access_modes;
      attachment_options^ [2].selector := fsc$create_file;
      attachment_options^ [2].create_file := FALSE;
      attachment_options^ [3].selector := fsc$open_position;
      attachment_options^ [3].open_position := amc$open_at_boi;
      attachment_options^ [4].selector := fsc$private_read;
      attachment_options^ [4].private_read := TRUE;
      attachment_options^ [5].selector := fsc$free_behind;
      attachment_options^ [5].free_behind := TRUE;
      attachment_options^ [6].selector := fsc$sequential_access;
      attachment_options^ [6].sequential_access := TRUE;

      fsp$open_file (log_file, amc$segment, attachment_options, NIL, NIL, NIL, NIL,
            new_open_log_file_descriptor_p^.bam_file_identifier, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      amp$get_segment_pointer (new_open_log_file_descriptor_p^.bam_file_identifier, amc$sequence_pointer,
            segment_pointer, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      RESET segment_pointer.sequence_pointer;
      new_open_log_file_descriptor_p^.file_reference := log_file;
      new_open_log_file_descriptor_p^.log_data := segment_pointer.sequence_pointer;
    IFEND;

{ Link the new open log file descriptor in the list.

    new_open_log_file_descriptor_p^.backward := NIL;
    new_open_log_file_descriptor_p^.forward := lgv$open_log_file_descriptor;
    IF lgv$open_log_file_descriptor <> NIL THEN
      lgv$open_log_file_descriptor^.backward := new_open_log_file_descriptor_p;
    IFEND;
    lgv$open_log_file_descriptor := new_open_log_file_descriptor_p;

  PROCEND lgp$open_log_file;
?? OLDTITLE ??
?? NEWTITLE := 'lgp$open_log_file_descriptor', EJECT ??

  FUNCTION [XDCL, #GATE] lgp$open_log_file_descriptor
    (    log_file_identifier: lgt$log_file_identifier): ^lgt$open_log_file_descriptor;

    VAR
      current_log_file_descriptor_p: ^lgt$open_log_file_descriptor;

    current_log_file_descriptor_p := lgv$open_log_file_descriptor;
    WHILE current_log_file_descriptor_p <> NIL DO
      IF current_log_file_descriptor_p^.log_file_identifier = log_file_identifier THEN
        lgp$open_log_file_descriptor := current_log_file_descriptor_p;
        RETURN;
      IFEND;
      current_log_file_descriptor_p := current_log_file_descriptor_p^.forward;
    WHILEND;
    lgp$open_log_file_descriptor := NIL;

  FUNCEND lgp$open_log_file_descriptor;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] lgp$rewind_log_file', EJECT ??
*copyc lgh$rewind_log_file

  PROCEDURE [XDCL, #GATE] lgp$rewind_log_file
    (    log_file_identifier: lgt$log_file_identifier;
     VAR status: ost$status);

    VAR
      ending_offset: amt$file_byte_address,
      log_file_descriptor_p: ^lgt$open_log_file_descriptor;

    status.normal := TRUE;

{ Find the open log file descriptor.

    log_file_descriptor_p := lgp$open_log_file_descriptor (log_file_identifier);
    IF log_file_descriptor_p = NIL THEN
      osp$set_status_abnormal ('LG', lge$unknown_log_file_identifier, log_file_identifier, status);
      RETURN;
    IFEND;

{ If this is an active log, get the current information about the log.

    IF log_file_descriptor_p^.active_log THEN
      IF log_file_descriptor_p^.global_log THEN
        lgp$get_global_log_read_info (log_file_descriptor_p^.log, 0, log_file_descriptor_p^.log_cycle,
              log_file_descriptor_p^.log_data, ending_offset, status);
      ELSE
        lgp$get_local_log_read_info (log_file_descriptor_p^.log, 0, log_file_descriptor_p^.log_cycle,
              log_file_descriptor_p^.log_data, ending_offset, status);
      IFEND;
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;

{ Reset the log data sequence pointer to start at the beginning.

    RESET log_file_descriptor_p^.log_data;

  PROCEND lgp$rewind_log_file;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] lgp$terminate_critical_log', EJECT ??
*copyc lgh$terminate_critical_log

  PROCEDURE [XDCL, #GATE] lgp$terminate_critical_log
    (    termination_file: fst$file_reference;
     VAR status: ost$status);

?? NEWTITLE := 'block_exit_handler', EJECT ??

{ PURPOSE:
{   This block exit condition handler makes sure the termination file is closed if an error occurs.

    PROCEDURE block_exit_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        ignore_status: ost$status;

      fsp$close_file (termination_file_id, ignore_status);

    PROCEND block_exit_handler;
?? OLDTITLE, EJECT ??

    VAR
      caller_identifier: ost$caller_identifier,
      file_attachment_options: ^fst$attachment_options,
      ignore_status: ost$status,
      mandated_creation_attributes: ^fst$file_cycle_attributes,
      termination_file_id: amt$file_identifier;

    status.normal := TRUE;
    #CALLER_ID (caller_identifier);

{ Verify that the user has the authority to terminate the critical window log.

    verify_authority (caller_identifier, pmc$system_log, {critical_window_log = } TRUE, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    osp$establish_block_exit_hndlr (^block_exit_handler);

{ Set up the file attributes for the termination file.

    PUSH file_attachment_options: [1 .. 1];
    file_attachment_options^ [1].selector := fsc$access_and_share_modes;
    file_attachment_options^ [1].access_modes.selector := fsc$specific_access_modes;
    file_attachment_options^ [1].access_modes.value := $fst$file_access_options
          [fsc$append, fsc$modify, fsc$shorten];
    file_attachment_options^ [1].share_modes.selector := fsc$specific_share_modes;
    file_attachment_options^ [1].share_modes.value := $fst$file_access_options [];

    PUSH mandated_creation_attributes: [1 .. 2];
    mandated_creation_attributes^ [1].selector := fsc$file_contents_and_processor;
    mandated_creation_attributes^ [1].file_contents := fsc$legible_data;
    mandated_creation_attributes^ [1].file_processor := fsc$unknown_processor;
    mandated_creation_attributes^ [2].selector := fsc$ring_attributes;
    mandated_creation_attributes^ [2].ring_attributes.r1 := caller_identifier.ring;
    mandated_creation_attributes^ [2].ring_attributes.r2 := caller_identifier.ring;
    mandated_creation_attributes^ [2].ring_attributes.r3 := caller_identifier.ring;

{ Open the termination file.

    fsp$open_file (termination_file, amc$record, file_attachment_options, {default_creation_attributes} NIL,
          mandated_creation_attributes, {attribute_validation} NIL, {attribute_override} NIL,
          termination_file_id, status);
    #SPOIL (termination_file_id);
    IF NOT status.normal THEN
      osp$disestablish_cond_handler;
      RETURN;
    IFEND;

{ Copy the log to the termination file and release any unneeded disk space.

    lgp$terminate_critical_log_proc (termination_file_id, status);

{ Close the termination file.

    fsp$close_file (termination_file_id, ignore_status);

    osp$disestablish_cond_handler;

  PROCEND lgp$terminate_critical_log;
?? OLDTITLE ??
?? NEWTITLE := 'lgp$terminate_critical_log_proc', EJECT ??
{ PURPOSE:
{   This request copies the existing log entries from an active log to another file and then releases the
{   unneeded disk space occupied by the active log.

  PROCEDURE lgp$terminate_critical_log_proc
    (    termination_file_id: amt$file_identifier;
     VAR status: ost$status);

    VAR
      byte_address: amt$file_byte_address,
      caller_identifier: ost$caller_identifier,
      critical_log_entry: ^pmt$system_log_entry,
      date: ost$date,
      end_of_log: boolean,
      ending_offset: amt$file_byte_address,
      first_log_entry_header_p: ^lgt$log_entry_header,
      global_task_id: ost$global_task_id,
      log_cycle: lgt$log_cycle,
      log_data: ^SEQ ( * ),
      log_entries_processed: integer,
      log_entry_p: ^lgt$log_entry,
      log_entry_size: lgt$log_entry_size,
      log_time: ost$time,
      message_text: ost$string,
      next_log_entry_header_p: ^lgt$log_entry_header,
      previous_log_data: ^SEQ ( * ),
      statistic: ^SEQ ( * ),
      statistic_descriptive_data: ^sft$descriptive_data,
      statistic_header: ^sft$statistic_header,
      termination_id: ost$name;

?? NEWTITLE := 'condition_handler', EJECT ??
{ PURPOSE:
{   This condition handler is used to handle interactive pause break and terminate break conditions.

    PROCEDURE condition_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        local_status: ost$status;

      IF condition.selector = ifc$interactive_condition THEN
        IF condition.interactive_condition = ifc$pause_break THEN
          ifp$invoke_pause_utility (local_status);
        ELSEIF condition.interactive_condition = ifc$terminate_break THEN
          osp$set_status_from_condition ('LG', condition, save_area, status, local_status);
          EXIT lgp$terminate_critical_log_proc;
        ELSE
          pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
        IFEND
      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
      IFEND;

    PROCEND condition_handler;
?? OLDTITLE, EJECT ??
    status.normal := TRUE;
    #CALLER_ID (caller_identifier);

{ Verify that the user has the authority to terminate the critical window log.

    verify_authority (caller_identifier, pmc$system_log, {critical_window_log = } TRUE, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Get the log data pointer and the current ending offset for the log.

    lgp$get_critical_log_read_info (0, log_cycle, log_data, ending_offset, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Construct the log termination message and place it in the appropriate log.

    pmp$get_unique_name (termination_id, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    pmp$get_date (osc$month_date, date, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    message_text.value := 'Log continued,  current date is';
    message_text.size := clp$trimmed_string_size (message_text.value);
    message_text.value (message_text.size + 2, * ) := date.month;
    message_text.size := clp$trimmed_string_size (message_text.value);
    message_text.value (message_text.size + 1, * ) := '.  Log termination identifier =';
    message_text.size := clp$trimmed_string_size (message_text.value);
    message_text.value (message_text.size + 2, * ) := termination_id;
    message_text.size := clp$trimmed_string_size (message_text.value);

    lgp$add_entry_to_critical_log (message_text.value (1, message_text.size), status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Allocate a log entry and construct pointers to the important information in the log entry.

    PUSH log_entry_p: [[REP lgc$maximum_log_entry_size OF cell]];
    RESET log_entry_p;
    NEXT critical_log_entry: [message_text.size] IN log_entry_p;

{ Copy the log entries from the beginning of the log until the log termination message is found.

    osp$establish_condition_handler (^condition_handler, FALSE);
    log_entries_processed := 0;

    RESET log_data;
    end_of_log := FALSE;

  /copy_log/
    REPEAT

{ Periodically allow signals and flags to be processed.  This allows the user to interupt the display.

      IF (log_entries_processed MOD lgc$signal_flag_process_count) = 0 THEN
        tmp$dispose_of_signals_flags (tmc$long_term_wait);
      IFEND;
      log_entries_processed := log_entries_processed + 1;

{ Save the log data pointer before the read so that it can be used to construct a pointer to the log entry
{ header for the log termination message when it is found.

      previous_log_data := log_data;

{ Get the next log entry.

      lgp$get_entry_from_critical_log (log_cycle, log_data, log_entry_size, log_entry_p^, status);
      IF NOT status.normal THEN
        IF status.condition = lge$end_of_log THEN
          status.normal := TRUE;
          end_of_log := TRUE;
          EXIT /copy_log/;
        ELSE
          osp$disestablish_cond_handler;
          RETURN;
        IFEND;
      IFEND;

{ Check if the log entry contains the log termination message.  If it does, update the message before writing
{ it to the termination file.

      IF i#current_sequence_position (log_data) > ending_offset THEN
        IF critical_log_entry^.text (1, message_text.size) = message_text.value (1, message_text.size) THEN
          critical_log_entry^.text (5, 11) := 'terminated,';
          end_of_log := TRUE;
        IFEND;
      IFEND;

{ Write the log entry to the termination file.

      amp$put_next (termination_file_id, log_entry_p, log_entry_size, byte_address, status);
      IF NOT status.normal THEN
        osp$disestablish_cond_handler;
        RETURN;
      IFEND;
    UNTIL end_of_log {/copy_log/} ;

    osp$disestablish_cond_handler;

{ Get a pointer to the log entry header for the log termination log entry.  This will be the first log entry
{ header when termination has completed.

    NEXT first_log_entry_header_p IN previous_log_data;
    IF first_log_entry_header_p = NIL THEN
      osp$set_status_abnormal ('LG', lge$corrupted_log, lgv$critical_log_name, status);
      RETURN;
    IFEND;

{ Move the log entries that were added since log termination began to the beginning of the log and release the
{ unneeded disk space.

    lgp$release_critical_log_space (log_cycle, first_log_entry_header_p, status);

  PROCEND lgp$terminate_critical_log_proc;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] lgp$terminate_log', EJECT ??
*copyc lgh$terminate_log

  PROCEDURE [XDCL, #GATE] lgp$terminate_log
    (    global_log: pmt$global_logs;
         termination_file: fst$file_reference;
     VAR status: ost$status);

?? NEWTITLE := 'block_exit_handler', EJECT ??

{ PURPOSE:
{   This block exit condition handler makes sure the termination file is closed if an error occurs.

    PROCEDURE block_exit_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        ignore_status: ost$status;

      fsp$close_file (termination_file_id, ignore_status);

    PROCEND block_exit_handler;
?? OLDTITLE, EJECT ??

    VAR
      caller_identifier: ost$caller_identifier,
      file_attachment_options: ^fst$attachment_options,
      ignore_status: ost$status,
      mandated_creation_attributes: ^fst$file_cycle_attributes,
      termination_file_id: amt$file_identifier;

    status.normal := TRUE;
    #CALLER_ID (caller_identifier);

{ Verify that a valid log ordinal has been specified.

    IF NOT (global_log IN -$pmt$global_logset []) THEN
      osp$set_status_abnormal ('LG', lge$incorrect_log_ordinal, 'LGP$TERMINATE_LOG', status);
      RETURN;
    IFEND;

{ Verify that the user has the authority to terminate the specified log.

    verify_authority (caller_identifier, global_log, {critical_window_log = } FALSE, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    osp$establish_block_exit_hndlr (^block_exit_handler);

{ Set up the file attributes for the termination file.

    PUSH file_attachment_options: [1 .. 1];
    file_attachment_options^ [1].selector := fsc$access_and_share_modes;
    file_attachment_options^ [1].access_modes.selector := fsc$specific_access_modes;
    file_attachment_options^ [1].access_modes.value := $fst$file_access_options
          [fsc$append, fsc$modify, fsc$shorten];
    file_attachment_options^ [1].share_modes.selector := fsc$specific_share_modes;
    file_attachment_options^ [1].share_modes.value := $fst$file_access_options [];

    PUSH mandated_creation_attributes: [1 .. 2];
    mandated_creation_attributes^ [1].selector := fsc$file_contents_and_processor;
    IF global_log = pmc$system_log THEN
      mandated_creation_attributes^ [1].file_contents := fsc$legible_data;
    ELSE
      mandated_creation_attributes^ [1].file_contents := fsc$binary_log;
    IFEND;
    mandated_creation_attributes^ [1].file_processor := fsc$unknown_processor;
    mandated_creation_attributes^ [2].selector := fsc$ring_attributes;
    mandated_creation_attributes^ [2].ring_attributes.r1 := caller_identifier.ring;
    mandated_creation_attributes^ [2].ring_attributes.r2 := caller_identifier.ring;
    mandated_creation_attributes^ [2].ring_attributes.r3 := caller_identifier.ring;

{ Open the termination file.

    fsp$open_file (termination_file, amc$record, file_attachment_options, {default_creation_attributes} NIL,
          mandated_creation_attributes, {attribute_validation} NIL, {attribute_override} NIL,
          termination_file_id, status);
    #SPOIL (termination_file_id);
    IF NOT status.normal THEN
      osp$disestablish_cond_handler;
      RETURN;
    IFEND;

{ Copy the log to the termination file and release any unneeded disk space.

    lgp$terminate_log_processor (global_log, termination_file_id, status);

{ Close the termination file.

    fsp$close_file (termination_file_id, ignore_status);

    osp$disestablish_cond_handler;

  PROCEND lgp$terminate_log;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] lgp$terminate_log_processor', EJECT ??
{ PURPOSE:
{   This request copies the existing log entries from an active log to another file and then releases the
{   unneeded disk space occupied by the active log.

  PROCEDURE [XDCL, #GATE] lgp$terminate_log_processor
    (    global_log: pmt$global_logs;
         termination_file_id: amt$file_identifier;
     VAR status: ost$status);

    VAR
      byte_address: amt$file_byte_address,
      caller_identifier: ost$caller_identifier,
      date: ost$date,
      end_of_log: boolean,
      ending_offset: amt$file_byte_address,
      first_log_entry_header_p: ^lgt$log_entry_header,
      global_task_id: ost$global_task_id,
      log_cycle: lgt$log_cycle,
      log_data: ^SEQ ( * ),
      log_entries_processed: integer,
      log_entry_p: ^lgt$log_entry,
      log_entry_size: lgt$log_entry_size,
      log_time: ost$time,
      message_text: ost$string,
      next_log_entry_header_p: ^lgt$log_entry_header,
      previous_log_data: ^SEQ ( * ),
      statistic: ^SEQ ( * ),
      statistic_descriptive_data: ^sft$descriptive_data,
      statistic_header: ^sft$statistic_header,
      system_log_entry: ^pmt$system_log_entry,
      termination_id: ost$name;

?? NEWTITLE := 'condition_handler', EJECT ??
{ PURPOSE:
{   This condition handler is used to handle interactive pause break and terminate break conditions.

    PROCEDURE condition_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        local_status: ost$status;

      IF condition.selector = ifc$interactive_condition THEN
        IF condition.interactive_condition = ifc$pause_break THEN
          ifp$invoke_pause_utility (local_status);
        ELSEIF condition.interactive_condition = ifc$terminate_break THEN
          osp$set_status_from_condition ('LG', condition, save_area, status, local_status);
          EXIT lgp$terminate_log_processor;
        ELSE
          pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
        IFEND
      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
      IFEND;

    PROCEND condition_handler;
?? OLDTITLE, EJECT ??
    status.normal := TRUE;
    #CALLER_ID (caller_identifier);

{ Verify that a valid log ordinal has been specified.

    IF NOT (global_log IN -$pmt$global_logset []) THEN
      osp$set_status_abnormal ('LG', lge$incorrect_log_ordinal, 'LGP$TERMINATE_LOG_PROCESSOR', status);
      RETURN;
    IFEND;

{ Verify that the user has the authority to terminate the specified log.

    verify_authority (caller_identifier, global_log, {critical_window_log = } FALSE, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Get the log data pointer and the current ending offset for the log.

    lgp$get_global_log_read_info (global_log, 0, log_cycle, log_data, ending_offset, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Construct the log termination message and place it in the appropriate log.

    pmp$get_unique_name (termination_id, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF global_log = pmc$system_log THEN
      pmp$get_date (osc$month_date, date, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      message_text.value := 'Log continued,  current date is';
      message_text.size := clp$trimmed_string_size (message_text.value);
      message_text.value (message_text.size + 2, * ) := date.month;
      message_text.size := clp$trimmed_string_size (message_text.value);
      message_text.value (message_text.size + 1, * ) := '.  Log termination identifier =';
      message_text.size := clp$trimmed_string_size (message_text.value);
      message_text.value (message_text.size + 2, * ) := termination_id;
      message_text.size := clp$trimmed_string_size (message_text.value);

      lgp$add_entry_to_system_log (pmc$msg_origin_system, message_text.value (1, message_text.size), log_time,
            status);
    ELSE
      message_text.value := 'Log termination identifier = ';
      message_text.size := clp$trimmed_string_size (message_text.value);
      message_text.value (message_text.size + 2, * ) := termination_id;
      message_text.size := clp$trimmed_string_size (message_text.value);

      PUSH statistic: [[REP (#SIZE (sft$statistic_header) + message_text.size) OF cell]];
      RESET statistic;

      pmp$get_executing_task_gtid (global_task_id);

      sfp$build_statistic (lgc$start_of_log, message_text.value (1, message_text.size), NIL, global_task_id,
            statistic, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      lgp$add_entry_global_binary_log (global_log, statistic, status);
    IFEND;
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Allocate a log entry and construct pointers to the important information in the log entry.

    PUSH log_entry_p: [[REP lgc$maximum_log_entry_size OF cell]];
    RESET log_entry_p;
    IF global_log = pmc$system_log THEN
      NEXT system_log_entry: [message_text.size] IN log_entry_p;
    ELSE
      NEXT statistic_header IN log_entry_p;
    IFEND;

{ Copy the log entries from the beginning of the log until the log termination message is found.

    osp$establish_condition_handler (^condition_handler, FALSE);
    log_entries_processed := 0;

    RESET log_data;
    end_of_log := FALSE;

  /copy_log/
    REPEAT

{ Periodically allow signals and flags to be processed.  This allows the user to interupt the display.

      IF (log_entries_processed MOD lgc$signal_flag_process_count) = 0 THEN
        tmp$dispose_of_signals_flags (tmc$long_term_wait);
      IFEND;
      log_entries_processed := log_entries_processed + 1;

{ Save the log data pointer before the read so that it can be used to construct a pointer to the log entry
{ header for the log termination message when it is found.

      previous_log_data := log_data;

{ Get the next log entry.

      lgp$get_entry_from_global_log (global_log, log_cycle, log_data, log_entry_size, log_entry_p^, status);
      IF NOT status.normal THEN
        IF status.condition = lge$end_of_log THEN
          status.normal := TRUE;
          end_of_log := TRUE;
          EXIT /copy_log/;
        ELSE
          osp$disestablish_cond_handler;
          RETURN;
        IFEND;
      IFEND;

{ Check if the log entry contains the log termination message.  If it does, update the message before writing
{ it to the termination file.

      IF i#current_sequence_position (log_data) > ending_offset THEN
        IF global_log = pmc$system_log THEN
          IF system_log_entry^.text (1, message_text.size) = message_text.value (1, message_text.size) THEN
            system_log_entry^.text (5, 11) := 'terminated,';
            end_of_log := TRUE;
          IFEND;
        ELSE
          IF ((statistic_header^.statistic_code = lgc$start_of_log) AND
                (statistic_header^.number_of_counters = 0) AND (statistic_header^.descriptive_data_size =
                message_text.size)) THEN
            NEXT statistic_descriptive_data: [statistic_header^.descriptive_data_size] IN log_entry_p;
            IF statistic_descriptive_data^ = message_text.value THEN
              statistic_header^.statistic_code := lgc$end_of_log;
              end_of_log := TRUE;
            ELSE
              RESET log_entry_p TO statistic_descriptive_data;
            IFEND;
          IFEND;
        IFEND;
      IFEND;

{ Write the log entry to the termination file.

      amp$put_next (termination_file_id, log_entry_p, log_entry_size, byte_address, status);
      IF NOT status.normal THEN
        osp$disestablish_cond_handler;
        RETURN;
      IFEND;
    UNTIL end_of_log {/copy_log/} ;

    osp$disestablish_cond_handler;

{ Get a pointer to the log entry header for the log termination log entry.  This will be the first log entry
{ header when termination has completed.

    NEXT first_log_entry_header_p IN previous_log_data;
    IF first_log_entry_header_p = NIL THEN
      osp$set_status_abnormal ('LG', lge$corrupted_log, lgv$log_names [global_log], status);
      RETURN;
    IFEND;

{ Move the log entries that were added since log termination began to the beginning of the log and release the
{ unneeded disk space.

    lgp$release_global_log_space (global_log, log_cycle, first_log_entry_header_p, status);

  PROCEND lgp$terminate_log_processor;
?? OLDTITLE ??
?? NEWTITLE := 'verify_authority', EJECT ??

{ PURPOSE:
{   Verifies that the user has the proper authority to read or terminate the specified log.

  PROCEDURE verify_authority
    (    caller_identifier: ost$caller_identifier;
         global_log: pmt$global_logs;
         critical_window_log: boolean;
     VAR status: ost$status);

    status.normal := TRUE;

{ If called from above ring six, check for proper capabilities.  Otherwise allow the access.

    IF caller_identifier.ring > osc$sj_ring_3 THEN
      IF critical_window_log THEN

{ Access to the critical window log requires system operation.

        IF NOT avp$system_operator () THEN
          osp$set_status_abnormal ('OF', ofe$sou_not_active, 'system_operation', status);
          RETURN;
        IFEND;

      ELSE
      CASE global_log OF
      = pmc$account_log =

{ Access to the account log requires accounting administration.

        IF NOT avp$accounting_administrator () THEN
          osp$set_status_abnormal ('OF', ofe$sou_not_active, 'accounting_administration', status);
          RETURN;
        IFEND;

      = pmc$engineering_log =

{ Access to the engineering log requires configuration administration.

        IF NOT avp$configuration_administrator () THEN
          osp$set_status_abnormal ('OF', ofe$sou_not_active, 'configuration_administration', status);
          RETURN;
        IFEND;

      = pmc$system_log, pmc$history_log =

{ Access to the system log or history log requires system operation.

        IF NOT avp$system_operator () THEN
          osp$set_status_abnormal ('OF', ofe$sou_not_active, 'system_operation', status);
          RETURN;
        IFEND;

      = pmc$security_log =

{ Access to the security log requires system administration.

        IF NOT avp$system_administrator () THEN
          osp$set_status_abnormal ('OF', ofe$sou_not_active, 'system_administration', status);
          RETURN;
        IFEND;

      = pmc$statistic_log =

{ Access to the statistics log requires configuration administration.

        IF NOT avp$configuration_administrator () THEN
          osp$set_status_abnormal ('OF', ofe$sou_not_active, 'configuration_administration', status);
          RETURN;
        IFEND;
      CASEND;
    IFEND;
    IFEND;

  PROCEND verify_authority;
?? OLDTITLE ??
MODEND lgm$logging_interfaces;
