*copy osd$default_pragmats
?? TITLE := 'RAM$DISPLAY_PREVIOUS_COMMANDS' ??
MODULE ram$display_previous_commands;

*copyc amp$get_next
*copyc amp$put_next
*copyc amp$put_partial
*copyc amp$rewind
*copyc amp$return
*copyc clp$get_value
*copyc clc$standard_file_names
*copyc clp$scan_command_line
*copyc clp$scan_parameter_list
*copyc clp$trimmed_string_size
*copyc fsp$close_file
*copyc fsp$open_file


  CONST
    rac$max_previous_commands = 0ffff(16);

  TYPE
    rat$previous_commands = 0..rac$max_previous_commands,
    circular_queue = ^queue_element,
    queue_element = record
      data: ost$string,
      forward: circular_queue,
      backward: circular_queue,
    recend;


  PROCEDURE create_circular_queue (number_of_nodes: rat$previous_commands;
    VAR head: circular_queue);

    VAR
      node: circular_queue,
      front: circular_queue,
      cnt: rat$previous_commands;

    ALLOCATE node;
    node^.data.value := ' ';
    node^.forward := NIL;
    node^.backward := NIL;

    front := node;
    head := node;

    FOR cnt := 2 TO number_of_nodes DO
      ALLOCATE node;
      node^.data.value := ' ';
      node^.forward := NIL;
      node^.backward := front;
      front^.forward := node;
      front := node;
    FOREND;

    head^.backward := front;
    front^.forward := head;

  PROCEND create_circular_queue;

  PROCEDURE generate_command_queue (number_of_commands: rat$previous_commands;
    VAR command_queue: circular_queue;
    VAR status: ost$status);

    VAR
      head: circular_queue,
      job_log_fid: amt$file_identifier,
      file_pos: amt$file_position,
      tran_cnt: amt$transfer_count,
      byte_adr: amt$file_byte_address,
      input_line: ost$string,
      previous_command: ost$string,
      attachment_option: array [1 .. 1] of fst$attachment_option,
      command_counter: rat$previous_commands;


    create_circular_queue (number_of_commands + 1, command_queue);
    head := command_queue;

    attachment_option [1].selector := fsc$access_and_share_modes;
    attachment_option [1].access_modes.selector := fsc$specific_access_modes;
    attachment_option [1].access_modes.value := $fst$file_access_options [fsc$read];
    attachment_option [1].share_modes.selector := fsc$specific_share_modes;
    attachment_option [1].share_modes.value := $fst$file_access_options [];

    fsp$open_file (clc$job_log, amc$record, ^attachment_option, NIL, NIL, NIL, NIL, job_log_fid, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    amp$rewind (job_log_fid, osc$wait, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    amp$get_next (job_log_fid, ^input_line, #SIZE (input_line), tran_cnt, byte_adr, file_pos, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    previous_command.value (1) := ' ';
    command_counter := 0;
    WHILE file_pos <> amc$eoi DO
      IF input_line.value (12, 2) = 'CI' THEN
        previous_command.value (2, * ) := input_line.value (15, * );
        previous_command.size := tran_cnt - 15;

        IF previous_command.size > 1 THEN
          command_counter := command_counter + 1;
          command_queue := command_queue^.forward;
          command_queue^.data := previous_command;
        IFEND
      IFEND;

      input_line.value :=
        '                                                                                      ';
      amp$get_next (job_log_fid, ^input_line, #SIZE (input_line), tran_cnt, byte_adr, file_pos, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    WHILEND;

    fsp$close_file (job_log_fid, status);

    IF command_counter <= number_of_commands THEN
      command_queue^.forward := head^.forward;
      head^.forward^.backward := command_queue;
    IFEND;

{ remove last command entered  (i.e. dispc) }
    command_queue^.forward^.backward := command_queue^.backward;
    command_queue^.backward^.forward := command_queue^.forward;
    command_queue := command_queue^.forward;
  PROCEND generate_command_queue;

?? NEWTITLE := 'RAP$DISPLAY_PREVIOUS_COMMANDS', EJECT ??
  PROCEDURE [XDCL, #GATE] rap$display_previous_commands (parameter_list: clt$parameter_list;
    VAR status: ost$status);

{ PDT  display_prev_cmd_pdt (
{   number_of_commands, noc, n: INTEGER 1..0ffff(16) = 24
{   output, o: file = $output
{   status)

?? PUSH (LISTEXT := ON) ??

  VAR
    display_prev_cmd_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [
      ^display_prev_cmd_pdt_names, ^display_prev_cmd_pdt_params];

  VAR
    display_prev_cmd_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 6] of
      clt$parameter_name_descriptor := [['NUMBER_OF_COMMANDS', 1], ['NOC', 1], ['N', 1], ['OUTPUT', 2], ['O',
      2], ['STATUS', 3]];

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

{ NUMBER_OF_COMMANDS NOC N }
    [[clc$optional_with_default, ^display_prev_cmd_pdt_dv1], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL,
      clc$integer_value, 1, 0ffff(16)]],

{ OUTPUT O }
    [[clc$optional_with_default, ^display_prev_cmd_pdt_dv2], 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
    display_prev_cmd_pdt_dv1: [STATIC, READ, cls$pdt_names_and_defaults] string (2) := '24';

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

?? POP ??

    VAR
      command_queue: circular_queue,
      head: circular_queue,
      byte_adr: amt$file_byte_address,
      display_lfn: amt$local_file_name,
      display_fid: amt$file_identifier,
      number_of_commands: rat$previous_commands,
      tran_cnt: amt$transfer_count,
      value: clt$value;


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

    clp$get_value ('NUMBER_OF_COMMANDS', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    number_of_commands := value.int.value;

    clp$get_value ('OUTPUT', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    fsp$open_file (value.file.local_file_name, amc$record, nil, NIL, NIL, NIL, NIL, display_fid, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    generate_command_queue (number_of_commands, command_queue, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    head := command_queue;
    REPEAT
      amp$put_next (display_fid, ^command_queue^.data.value, command_queue^.data.size, byte_adr, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      command_queue := command_queue^.forward;
    UNTIL command_queue = head;

    fsp$close_file (display_fid, status);

  PROCEND rap$display_previous_commands;

?? OLDTITLE, NEWTITLE := 'RAP$MODIFY_PREVIOUS_COMMANDS', EJECT ??
  PROCEDURE [XDCL, #GATE] rap$modify_previous_commands (parameter_list: clt$parameter_list;
    VAR status: ost$status);


{ PDT modify_pc_pdt (
{   commands_back, cb: integer 1..100 = 1
{   status)

?? PUSH (LISTEXT := ON) ??

  VAR
    modify_pc_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^modify_pc_pdt_names,
      ^modify_pc_pdt_params];

  VAR
    modify_pc_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 3] of
      clt$parameter_name_descriptor := [['COMMANDS_BACK', 1], ['CB', 1], ['STATUS', 2]];

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

{ COMMANDS_BACK CB }
    [[clc$optional_with_default, ^modify_pc_pdt_dv1], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL,
      clc$integer_value, 1, 100]],

{ STATUS }
    [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$variable_reference,
      clc$array_not_allowed, clc$status_value]]];

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

?? POP ??

    VAR
      command_queue: circular_queue,
      head: circular_queue,
      byte_adr: amt$file_byte_address,
      display_lfn: [STATIC] amt$local_file_name := '$OUTPUT',
      display_fid: amt$file_identifier,
      edit_line: ost$string,
      queue_size: rat$previous_commands,
      tran_cnt: amt$transfer_count,
      value: clt$value;


    PROCEDURE modify_line (VAR old: ost$string;
      VAR status: ost$status);

      VAR
        changes: ost$string,
        chng_cnt: 0 .. 256,
        difference: - 256 .. 256,
        max_length: 0 .. 256,
        new: ost$string,
        new_cnt: 0 .. 256,
        old_cnt: 0 .. 256,
        display_line: string (256),
        input_fid: amt$file_identifier,
        input_lfn: [STATIC] amt$local_file_name := '$INPUT',
        prompt: [STATIC] string (3) := ' ==',
        file_pos: amt$file_position,
        tran_cnt: amt$transfer_count;


      fsp$open_file (input_lfn, amc$record, NIL, NIL, NIL, NIL, NIL, input_fid, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      display_line (1, 5) := ' ==> ';
      display_line (6, * ) := old.value (1, old.size);
      amp$put_next (display_fid, ^display_line, old.size + 5, byte_adr, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      amp$put_partial (display_fid, ^prompt, #SIZE (prompt), byte_adr, amc$start, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      amp$get_next (input_fid, ^changes.value, #SIZE (changes.value),
            tran_cnt, byte_adr, file_pos, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      fsp$close_file (input_fid, status);

      changes.size := tran_cnt;

      IF old.size < changes.size THEN
        max_length := changes.size;
      ELSE
        IF changes.size = 0 THEN
          RETURN;
        ELSE
          max_length := old.size;
        IFEND;
      IFEND;

      difference := 0;
      old_cnt := 1;
      new_cnt := 1;

      /process_line/
      WHILE old_cnt <= max_length DO
        IF old_cnt > changes.size THEN
          WHILE old_cnt <= old.size DO
            new.value (new_cnt) := old.value (old_cnt);
            old_cnt := old_cnt + 1;
            new_cnt := old_cnt - difference;
          WHILEND;
          EXIT /process_line/;
        IFEND;

        CASE changes.value (old_cnt) OF
        = '&' =
          new.value (new_cnt) := ' ';

        = ' ' =
          IF old_cnt <= old.size THEN
            new.value (new_cnt) := old.value (old_cnt);
          ELSE
            new.value (new_cnt) := ' ';
          IFEND;

        = '#' =
          difference := difference + 1;

        = '^' =
          chng_cnt := old_cnt + 1;
          WHILE (changes.value (chng_cnt) <> '#') AND (chng_cnt <= changes.size) DO
            new.value (new_cnt) := changes.value (chng_cnt);
            chng_cnt := chng_cnt + 1;
            difference := difference - 1;
            new_cnt := old_cnt - difference;
          WHILEND;

          WHILE old_cnt < chng_cnt DO
            new.value (new_cnt) := old.value (old_cnt);
            old_cnt := old_cnt + 1;
            new_cnt := old_cnt - difference;
          WHILEND;
          new.value (new_cnt) := old.value (old_cnt);

        ELSE
          new.value (new_cnt) := changes.value (old_cnt);
        CASEND;

        old_cnt := old_cnt + 1;
        new_cnt := old_cnt - difference;

      WHILEND /process_line/;

      new.size := new_cnt;
      new.value(2,*) := new.value(1,*);
      new.value(1) := ' ';
      old := new;

      amp$put_next (display_fid, ^old.value (1, old.size), old.size, byte_adr, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

    PROCEND modify_line;

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

    clp$get_value ('COMMANDS_BACK', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    queue_size := value.int.value;


    fsp$open_file (display_lfn, amc$record, NIL, NIL, NIL, NIL, NIL, display_fid, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    generate_command_queue (queue_size, command_queue, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    edit_line.value := command_queue^.data.value(2,*);
    edit_line.size := command_queue^.data.size - 1;

    modify_line (edit_line, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clp$scan_command_line (edit_line.value (1, edit_line.size), status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    fsp$close_file (display_fid, status);

  PROCEND rap$modify_previous_commands;
MODEND ram$display_previous_commands;
