?? RIGHT := 110 ??
?? NEWTITLE := 'MODULE nfm$emulate_format_effectors' ??
MODULE nfm$emulate_format_effectors;

{ PURPOSE:
{   Translate a file containing ASCII format effectors into a file which
{   contains only NOS/VE batch format effectors.
{
{ DESIGN:
{   Examine the input file on a character by character basis.  Simulate the
{   activity caused by ASCII format effectors (BS, CR, HT, LF, FF, etc.) and
{   generate output containing equivalent batch format effectors.
{
{ NOTES:
{   This filter truncates output lines to conform to the PAGE_WIDTH parameter.
{   To facilitate truncation, coded files are positioned to the next record when
{   the output line is written, and transparent files are searched for the
{   transparent end of line character.
{
{   Although the path to a permanent file may be specified for the OUTPUT
{   parameter, use of permanent files is strongly discouraged.  Additionally,
{   this procedure will return an abnormal status if the path supplied for the
{   OUTPUT parameter specifies a file which already exists.

?? NEWTITLE := 'Global Declarations Referenced by This Module.', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cle$ecc_parsing
*copyc cle$incompatible_params_given
?? POP ??
*copyc amp$get_file_attributes
*copyc amp$get_next
*copyc amp$get_partial
*copyc amp$put_next
*copyc clp$change_variable
*copyc clp$evaluate_parameters
*copyc clp$get_variable_value
*copyc clp$trimmed_string_size
*copyc fsp$close_file
*copyc fsp$open_file
*copyc jmp$close_output_file
*copyc jmp$open_output_file
*copyc osp$append_status_parameter
*copyc osp$set_status_abnormal
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

  CONST
    bs = $CHAR (8),
    cr = $CHAR (13),
    first_text_column = 2,
    format_effector = 1,
    ff = $CHAR (12),
    ht = $CHAR (9),
    lf = $CHAR (10),
    maximum_input_bytes = 2048,
    maximum_output_bytes = 256,
    maximum_tab_stop = 255,
    us = $CHAR (31),
    vt = $CHAR (11);

  TYPE
    output_line_list = record
      line: string (maximum_output_bytes),
      next_line: ^output_line_list,
    recend;

  TYPE
    tab_stop_definition = packed array [0 .. maximum_tab_stop] of 0 .. 1;

?? OLDTITLE ??
?? NEWTITLE := 'PROCEDURE nfp$emaulte_ascii__filter', EJECT ??

  PROCEDURE [XDCL] nfp$emulate_format_effectors
    (    parameter_list: clt$parameter_list;
     VAR status: ost$status);

{ PROCEDURE emulate_ascii_format_effectors, emuafe (
{   input, i: record
{       system_file_name: name 19..19
{       password: string 1..31
{       file: file = $optional
{     recend = $required
{   output, o: file = $required
{   horizontal_tab_stops, hts: any of
{       key
{         none, standard
{       keyend
{       list of integer 0..255
{     anyend = none
{   transparent_end_of_line, teol: key
{       cr, lf
{     keyend = lf
{   vertical_tab_stops, vts: any of
{       key
{         none
{       keyend
{       list of integer 0..255
{     anyend = $optional
{   data_mode, dm: (VAR) key
{       (coded, c)
{       (transparent, t)
{     keyend = $required
{   page_length, pl: integer 1..4398046511103 = $required
{   page_width, pw: integer 10..255 = $required
{   status)

?? PUSH (LISTEXT := ON) ??
?? FMT (FORMAT := OFF) ??

  VAR
    pdt: [STATIC, READ, cls$declaration_section] record
      header: clt$pdt_header,
      names: array [1 .. 17] of clt$pdt_parameter_name,
      parameters: array [1 .. 9] of clt$pdt_parameter,
      type1: record
        header: clt$type_specification_header,
        qualifier: clt$record_type_qualifier,
        field_spec_1: clt$field_specification,
        element_type_spec_1: record
          header: clt$type_specification_header,
          qualifier: clt$name_type_qualifier,
          recend,
          field_spec_2: clt$field_specification,
          element_type_spec_2: record
            header: clt$type_specification_header,
            qualifier: clt$string_type_qualifier,
            recend,
            field_spec_3: clt$field_specification,
            element_type_spec_3: record
              header: clt$type_specification_header,
              recend,
              recend,
              type2: record
                header: clt$type_specification_header,
                recend,
                type3: record
                  header: clt$type_specification_header,
                  qualifier: clt$union_type_qualifier,
                  type_size_1: clt$type_specification_size,
                  element_type_spec_1: record
                    header: clt$type_specification_header,
                    qualifier: clt$keyword_type_qualifier,
                    keyword_specs: array [1 .. 2] of clt$keyword_specification,
                    recend,
                    type_size_2: clt$type_specification_size,
                    element_type_spec_2: record
                      header: clt$type_specification_header,
                      qualifier: clt$list_type_qualifier_v2,
                      element_type_spec: record
                        header: clt$type_specification_header,
                        qualifier: clt$integer_type_qualifier,
                        recend,
                        recend,
                        default_value: string (4),
                        recend,
                        type4: record
                          header: clt$type_specification_header,
                          qualifier: clt$keyword_type_qualifier,
                          keyword_specs: array [1 .. 2] of clt$keyword_specification,
                          default_value: string (2),
                          recend,
                          type5: record
                            header: clt$type_specification_header,
                            qualifier: clt$union_type_qualifier,
                            type_size_1: clt$type_specification_size,
                            element_type_spec_1: record
                              header: clt$type_specification_header,
                              qualifier: clt$keyword_type_qualifier,
                              keyword_specs: array [1 .. 1] of clt$keyword_specification,
                              recend,
                              type_size_2: clt$type_specification_size,
                              element_type_spec_2: record
                                header: clt$type_specification_header,
                                qualifier: clt$list_type_qualifier_v2,
                                element_type_spec: record
                                  header: clt$type_specification_header,
                                  qualifier: clt$integer_type_qualifier,
                                  recend,
                                  recend,
                                  recend,
                                  type6: record
                                    header: clt$type_specification_header,
                                    qualifier: clt$keyword_type_qualifier,
                                    keyword_specs: array [1 .. 4] of clt$keyword_specification,
                                    recend,
                                    type7: record
                                      header: clt$type_specification_header,
                                      qualifier: clt$integer_type_qualifier,
                                      recend,
                                      type8: record
                                        header: clt$type_specification_header,
                                        qualifier: clt$integer_type_qualifier,
                                        recend,
                                        type9: record
                                        header: clt$type_specification_header,
                                        recend,
    recend := [
    [1,
    [90, 8, 13, 13, 0, 37, 819],
    clc$command, 17, 9, 5, 0, 0, 1, 9, ''], [
    ['DATA_MODE                      ',clc$nominal_entry, 6],
    ['DM                             ',clc$abbreviation_entry, 6],
    ['HORIZONTAL_TAB_STOPS           ',clc$nominal_entry, 3],
    ['HTS                            ',clc$abbreviation_entry, 3],
    ['I                              ',clc$abbreviation_entry, 1],
    ['INPUT                          ',clc$nominal_entry, 1],
    ['O                              ',clc$abbreviation_entry, 2],
    ['OUTPUT                         ',clc$nominal_entry, 2],
    ['PAGE_LENGTH                    ',clc$nominal_entry, 7],
    ['PAGE_WIDTH                     ',clc$nominal_entry, 8],
    ['PL                             ',clc$abbreviation_entry, 7],
    ['PW                             ',clc$abbreviation_entry, 8],
    ['STATUS                         ',clc$nominal_entry, 9],
    ['TEOL                           ',clc$abbreviation_entry, 4],
    ['TRANSPARENT_END_OF_LINE        ',clc$nominal_entry, 4],
    ['VERTICAL_TAB_STOPS             ',clc$nominal_entry, 5],
    ['VTS                            ',clc$abbreviation_entry, 5]],
    [
{ PARAMETER 1
    [6, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation, clc$standard_parameter_checking, 131,
  clc$required_parameter, 0, 0],
{ PARAMETER 2
    [8, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation, clc$standard_parameter_checking, 3, clc$required_parameter, 0
  , 0],
{ PARAMETER 3
    [3, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation, clc$standard_parameter_checking, 137,
  clc$optional_default_parameter, 0, 4],
{ PARAMETER 4
    [15, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation, clc$standard_parameter_checking, 81,
  clc$optional_default_parameter, 0, 2],
{ PARAMETER 5
    [16, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation, clc$standard_parameter_checking, 100,
  clc$optional_parameter, 0, 0],
{ PARAMETER 6
    [1, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_reference, clc$immediate_evaluation, clc$standard_parameter_checking, 155,
  clc$required_parameter, 0, 0],
{ PARAMETER 7
    [9, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation, clc$standard_parameter_checking, 20, clc$required_parameter,
  0, 0],
{ PARAMETER 8
    [10, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name, clc$specify_positionally],
    clc$pass_by_value, clc$immediate_evaluation, clc$standard_parameter_checking, 20, clc$required_parameter,
  0, 0],
{ PARAMETER 9
    [13, clc$normal_usage_entry, clc$non_secure_parameter,
    $clt$parameter_spec_methods[clc$specify_by_name],
    clc$pass_by_reference, clc$immediate_evaluation, clc$standard_parameter_checking, 3,
  clc$optional_parameter, 0, 0]],
{ PARAMETER 1
    [[1, 0, clc$record_type], [3],
    ['SYSTEM_FILE_NAME               ', clc$required_field, 5], [[1, 0, clc$name_type], [19, 19]],
      ['PASSWORD                       ', clc$required_field, 8], [[1, 0, clc$string_type], [1, 31, FALSE]],
        ['FILE                           ', clc$optional_field, 3], [[1, 0, clc$file_type]]
          ],
{ PARAMETER 2
          [[1, 0, clc$file_type]],
{ PARAMETER 3
          [[1, 0, clc$union_type], [[clc$keyword_type, clc$list_type],
          FALSE, 2],
          81, [[1, 0, clc$keyword_type], [2], [
            ['NONE                           ', clc$nominal_entry, clc$normal_usage_entry, 1],
            ['STANDARD                       ', clc$nominal_entry, clc$normal_usage_entry, 2]]
            ],
            36, [[1, 0, clc$list_type], [20, 1, clc$max_list_size, 0, FALSE, FALSE],
                [[1, 0, clc$integer_type], [0, 255, 10]]
                ]
                ,
                'none'],
{ PARAMETER 4
                [[1, 0, clc$keyword_type], [2], [
                ['CR                             ', clc$nominal_entry, clc$normal_usage_entry, 1],
                ['LF                             ', clc$nominal_entry, clc$normal_usage_entry, 2]]
                ,
                'lf'],
{ PARAMETER 5
                [[1, 0, clc$union_type], [[clc$keyword_type, clc$list_type],
                FALSE, 2],
                44, [[1, 0, clc$keyword_type], [1], [
                  ['NONE                           ', clc$nominal_entry, clc$normal_usage_entry, 1]]
                  ],
                  36, [[1, 0, clc$list_type], [20, 1, clc$max_list_size, 0, FALSE, FALSE],
                      [[1, 0, clc$integer_type], [0, 255, 10]]
                      ]
                      ],
{ PARAMETER 6
                      [[1, 0, clc$keyword_type], [4], [
                      ['C                              ', clc$abbreviation_entry, clc$normal_usage_entry, 1],
                      ['CODED                          ', clc$nominal_entry, clc$normal_usage_entry, 1],
                      ['T                              ', clc$abbreviation_entry, clc$normal_usage_entry, 2],
                      ['TRANSPARENT                    ', clc$nominal_entry, clc$normal_usage_entry, 2]]
                      ],
{ PARAMETER 7
                      [[1, 0, clc$integer_type], [1, 4398046511103, 10]],
{ PARAMETER 8
                      [[1, 0, clc$integer_type], [10, 255, 10]],
{ PARAMETER 9
                      [[1, 0, clc$status_type]]];

?? FMT (FORMAT := ON) ??
?? POP ??

    CONST
      p$input = 1,
      p$output = 2,
      p$horizontal_tab_stops = 3,
      p$transparent_end_of_line = 4,
      p$vertical_tab_stops = 5,
      p$data_mode = 6,
      p$page_length = 7,
      p$page_width = 8,
      p$status = 9;

    VAR
      pvt: array [1 .. 9] of clt$parameter_value;

    CONST
      file_field = 3,
      p$teol = p$transparent_end_of_line,
      password_field = 2,
      sfn_field = 1;

{ Variables used for reading & containing input data.

    VAR
      ignored_record_size: amt$max_record_length,
      input_file_byte_address: amt$file_byte_address,
      input_file_byte_count: amt$transfer_count,
      input_file_id: amt$file_identifier,
      input_file_position: amt$file_position,
      input_file_prev_opened: boolean,
      input_line: string (maximum_input_bytes),
      input_line_index: integer;

{ Variables used to process input & output data.

    VAR
      blank_line: string (maximum_output_bytes),
      data_mode_value: ^clt$data_value,
      file_attachment_options: ^fst$attachment_options,
      file_attributes: array [1 .. 1] of amt$get_item,
      h_tab_stops: tab_stop_definition,
      local_status: ost$status,
      misc_index: integer,
      next_vertical_tab: integer,
      number_of_output_bytes: 1 .. 256,
      output_line_altered: boolean,
      search_character_found: boolean,
      tab_list_entry: ^clt$data_value,
      teol_character: string (1),
      v_tab_stops: tab_stop_definition;

{ Variables used for containing & writing output data.

    VAR
      current_line: ^output_line_list,
      cycle_attributes: ^fst$file_cycle_attributes,
      file_prev_opened: boolean,
      first_overstrike_line: ^output_line_list,
      ignored_file_contains_data: boolean,
      ignored_file_exists: boolean,
      new_line: ^output_line_list,
      output_file_byte_address: amt$file_byte_address,
      output_file_id: amt$file_identifier,
      output_line: string (maximum_output_bytes),
      output_line_count: integer,
      output_line_index: integer;

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

    PROCEDURE write_output_lines
      (VAR first_overstrike_line: ^output_line_list;
       VAR output_file_byte_address: amt$file_byte_address;
       VAR output_file_id: amt$file_identifier;
       VAR output_line: string (maximum_output_bytes);
       VAR output_line_altered: boolean;
       VAR output_line_count: integer;
       VAR number_of_output_bytes: 1 .. 256;
       VAR status: ost$status);

      VAR
        trimmed_string_size: integer,
        current_line: ^output_line_list;

      trimmed_string_size := number_of_output_bytes;
      trimmed_string_size := clp$trimmed_string_size(output_line);
      amp$put_next (output_file_id, ^output_line (1, trimmed_string_size), number_of_output_bytes,
            output_file_byte_address, status);
      IF status.normal THEN
        current_line := first_overstrike_line;
        WHILE current_line <> NIL DO
          output_line := current_line^.line;
          trimmed_string_size := clp$trimmed_string_size(output_line);
          amp$put_next (output_file_id, ^output_line (1, trimmed_string_size), number_of_output_bytes,
                output_file_byte_address, status);
          IF NOT status.normal THEN
            RETURN;
          IFEND;
          current_line := current_line^.next_line;
          FREE first_overstrike_line;
          first_overstrike_line := current_line;
        WHILEND;

{ Increment the output line count and rest the output line to blanks.

        output_line := blank_line (1, number_of_output_bytes);
        output_line_altered := FALSE;
        output_line_count := output_line_count + 1;
      IFEND;

    PROCEND write_output_lines;
?? OLDTITLE ??
?? EJECT ??

{   BEGIN nfp$emulate_format_effectors;

    status.normal := TRUE;

{ Validate the parameters passed to this procedure. Return to the caller on error.

    clp$evaluate_parameters (parameter_list, #SEQ (pdt), NIL, ^pvt, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Process the INPUT parameter. Note that memory is obtained to store file attachment
{ options unconditionally because it will be used at least once when the output
{ file is openned.

    PUSH file_attachment_options: [1 .. 1];

    IF pvt [p$input].value^.field_values^ [file_field].value = NIL THEN

{ The input file is the original queue file in the output queue.


      jmp$open_output_file (pvt [p$input].value^.field_values^ [sfn_field].
            value^.name_value (1, jmc$system_supplied_name_size), amc$record, jmc$public_usage,
            pvt [p$input].value^.field_values^ [password_field].value^.string_value^, input_file_id, status);

    ELSE

{ The input file is the output of another filter. Ignore the original queue file.

      file_attachment_options^ [1].selector := fsc$create_file;
      file_attachment_options^ [1].create_file := FALSE;
      fsp$open_file (pvt [p$input].value^.field_values^ [file_field].value^.file_value^, amc$record,
            file_attachment_options, NIL, NIL, NIL, NIL, input_file_id, status);
    IFEND;
    IF NOT status.normal THEN

{ Return to the caller of this procedure with the abnormal status from the
{ attempt to open file input file.

      RETURN;
    IFEND;

{ Process the OUTPUT parameter.  Return an abnormal status if the output file
{ already exists.


    file_attributes [1].key := amc$null_attribute;
    amp$get_file_attributes (pvt [p$output].value^.file_value^, file_attributes, ignored_file_exists,
          file_prev_opened, ignored_file_contains_data, status);

    IF status.normal AND file_prev_opened THEN
      osp$set_status_abnormal ('PF', pfe$duplicate_cycle, pvt [p$output].value^.file_value^, status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'specified', status);
      RETURN;
    IFEND;
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    PUSH cycle_attributes: [1 .. 6];

{ File contents, page format, page length, and page width attributes are
{ specified to provide accurate file attributes to other batch output filters
{ which may process the output of this filter, and to prevent any COPY_FILE
{ command (in SCL batch output filters) from attempting to 'burst' the file
{ contents.

    cycle_attributes^ [1].selector := fsc$file_contents_and_processor;
    cycle_attributes^ [1].file_contents := 'LIST';
    cycle_attributes^ [1].file_processor := osc$null_name;

    cycle_attributes^ [2].selector := fsc$page_format;
    cycle_attributes^ [2].page_format := amc$continuous_form;

    cycle_attributes^ [3].selector := fsc$page_length;
    cycle_attributes^ [3].page_length := pvt [p$page_length].value^.integer_value.value;

    cycle_attributes^ [4].selector := fsc$page_width;
    cycle_attributes^ [4].page_width := pvt [p$page_width].value^.integer_value.value;

{ Record delimiting character and record type are specified for compatibility
{ with BTF/VE.  Other record types must NOT be used.

    cycle_attributes^ [5].selector := fsc$record_delimiting_character;
    cycle_attributes^ [5].record_delimiting_character := us;

    cycle_attributes^ [6].selector := fsc$record_type;
    cycle_attributes^ [6].record_type := amc$trailing_char_delimited;

    file_attachment_options^ [1].selector := fsc$create_file;
    file_attachment_options^ [1].create_file := TRUE;


    fsp$open_file (pvt [p$output].value^.file_value^, amc$record, file_attachment_options, NIL,
          cycle_attributes, NIL, NIL, output_file_id, status);

    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Prepare to process the HORIZONTAL_TAB_STOPS parameter by initializing both tab
{ stop definitions to zero.  Because the array boundries are very similar,
{ initilize the variable BLANK_LINE in the same loop.

    FOR misc_index := 0 TO pvt [p$page_width].value^.integer_value.value DO
      v_tab_stops [misc_index] := 0;
      blank_line (misc_index + 1) := ' ';
    FOREND;
    h_tab_stops := v_tab_stops;

    IF pvt [p$horizontal_tab_stops].specified THEN
      IF (pvt [p$horizontal_tab_stops].value^.kind = clc$keyword) THEN
        IF (pvt [p$horizontal_tab_stops].value^.keyword_value (1, 8) = 'STANDARD') THEN
          FOR misc_index := 9 TO pvt [p$page_width].value^.integer_value.value DO
            IF (misc_index MOD 9) = 0 THEN
              h_tab_stops [misc_index] := 1;
            IFEND;
          FOREND;
        IFEND;
      ELSE { scan the list of tab stops specified.
        tab_list_entry := pvt [p$horizontal_tab_stops].value;
        WHILE tab_list_entry <> NIL DO
          h_tab_stops [tab_list_entry^.element_value^.integer_value.value] := 1;
          tab_list_entry := tab_list_entry^.link;
        WHILEND;
      IFEND;
    IFEND;

{ Process the TRANSPARENT_END_OF_LINE parameter.

    IF (pvt [p$teol].value^.keyword_value (1, 2) = 'CR') THEN
      teol_character := cr;
    ELSE
      teol_character := lf;
    IFEND;

{ Process the VERTICAL_TAB_STOPS parameter.

    IF pvt [p$vertical_tab_stops].specified AND (pvt [p$vertical_tab_stops].value^.kind <> clc$keyword) THEN
      tab_list_entry := pvt [p$vertical_tab_stops].value;
      WHILE tab_list_entry <> NIL DO
        v_tab_stops [tab_list_entry^.element_value^.integer_value.value] := 1;
        tab_list_entry := tab_list_entry^.link;
      WHILEND;
    IFEND;

{ Process the DATA_MODE parameter by obtaining the value of the variable
{ specified.


    clp$get_variable_value (pvt [p$data_mode].variable^, data_mode_value, status);

    IF NOT status.normal THEN

      RETURN;
    IFEND;


{ Prepare to enter the main processing loops.

    current_line := NIL;
    first_overstrike_line := NIL;
    input_line_index := 1;
    number_of_output_bytes := pvt [p$page_width].value^.integer_value.value + format_effector;
    output_line := blank_line (1, number_of_output_bytes);
    output_line_altered := FALSE;
    output_line_count := 0;
    output_line_index := first_text_column;

{ Prime the input buffer.

    amp$get_next (input_file_id, ^input_line, maximum_input_bytes, input_file_byte_count,
          input_file_byte_address, input_file_position, status);

    WHILE (input_file_position <> amc$eoi) AND status.normal DO
      WHILE (input_line_index <= input_file_byte_count) AND (output_line_index <= number_of_output_bytes) DO
        CASE input_line (input_line_index) OF
        = bs =
          IF output_line_index > first_text_column THEN
            output_line_index := output_line_index - 1;
          IFEND;

        = cr =
          IF (data_mode_value^.keyword_value (1, 11) = 'TRANSPARENT') AND (teol_character = cr) THEN
            write_output_lines (first_overstrike_line, output_file_byte_address, output_file_id, output_line,
                  output_line_altered, output_line_count, number_of_output_bytes, status);
            IF NOT status.normal THEN
              RETURN;
            IFEND;
          IFEND;

          output_line_index := first_text_column;

        = ff =

{ Only write the output line(s) if character data was actually inserted into the
{ output buffer.

          IF output_line_altered THEN
            write_output_lines (first_overstrike_line, output_file_byte_address, output_file_id, output_line,
                  output_line_altered, output_line_count, number_of_output_bytes, status);
            IF NOT status.normal THEN
              RETURN;
            IFEND;
          IFEND;

          output_line (format_effector) := '1';
          output_line_altered := TRUE;
          output_line_count := 0;

        = ht =
          IF pvt [p$horizontal_tab_stops].specified THEN
            misc_index := output_line_index;
            WHILE (h_tab_stops [misc_index] <> 1) AND (misc_index <
                  pvt [p$page_width].value^.integer_value.value) DO
              misc_index := misc_index + 1;
            WHILEND;
            IF misc_index < pvt [p$page_width].value^.integer_value.value THEN
              output_line_index := misc_index + 1;
            IFEND;
            output_line_altered := TRUE;
          IFEND;

        = lf =
          write_output_lines (first_overstrike_line, output_file_byte_address, output_file_id, output_line,
                output_line_altered, output_line_count, number_of_output_bytes, status);
          IF NOT status.normal THEN
            RETURN;
          IFEND;

          IF (data_mode_value^.keyword_value (1, 11) = 'TRANSPARENT') AND (teol_character = lf) THEN
            output_line_index := first_text_column;
          IFEND;

        = vt =
          IF pvt [p$vertical_tab_stops].specified AND (pvt [p$vertical_tab_stops].value^.kind <>
                clc$keyword) THEN
            write_output_lines (first_overstrike_line, output_file_byte_address, output_file_id, output_line,
                  output_line_altered, output_line_count, number_of_output_bytes, status);
            IF NOT status.normal THEN
              RETURN;
            IFEND;

            next_vertical_tab := pvt [p$page_length].value^.integer_value.value;
            misc_index := output_line_count MOD pvt [p$page_length].value^.integer_value.value;
            WHILE (v_tab_stops [misc_index] <> 1) AND ((misc_index <= maximum_tab_stop) AND
                  (misc_index < next_vertical_tab)) DO
              misc_index := misc_index + 1;
            WHILEND;

            IF (misc_index <= maximum_tab_stop) AND (misc_index < next_vertical_tab) THEN
              next_vertical_tab := misc_index;
            IFEND;

            misc_index := output_line_count MOD next_vertical_tab;
            WHILE (misc_index > 0) AND status.normal DO
              amp$put_next (output_file_id, ^output_line (1, 2), number_of_output_bytes,
                    output_file_byte_address, status);
              output_line_index := output_line_index + 1;
              misc_index := output_line_count MOD next_vertical_tab;
            WHILEND;
          IFEND;
        ELSE

{ The input character is not an ASCII format effector recognized by this filter.

          IF ($INTEGER (input_line (input_line_index)) > 31) AND
                ($INTEGER (input_line (input_line_index)) <> 127) THEN


{ If the output line index points to a blank in the output buffer than that
{ blank can be replaced by the input character.  If the output line index points
{ to a non-blank character in the output buffer, then this filter must generate
{ overstrike lines to cause the printer to print two characters at the same
{ physical location on the printed page.

            IF output_line (output_line_index) = ' ' THEN
              output_line (output_line_index) := input_line (input_line_index);
            ELSE

{ Find an overstrike line with a blank in the current position on the output
{ line. Create an overstrike line if none exists.

              IF (first_overstrike_line = NIL) THEN
                ALLOCATE first_overstrike_line;
                first_overstrike_line^.next_line := NIL;
                first_overstrike_line^.line := blank_line (1, number_of_output_bytes);
                first_overstrike_line^.line (format_effector) := '+';
                first_overstrike_line^.line (output_line_index) := input_line (input_line_index);
              ELSE
                current_line := first_overstrike_line;
                search_character_found := FALSE;
                WHILE NOT search_character_found DO
                  IF current_line^.line (output_line_index) = ' ' THEN
                    search_character_found := TRUE;
                  ELSEIF current_line^.next_line = NIL THEN
                    search_character_found := TRUE;
                    ALLOCATE new_line;
                    current_line^.next_line := new_line;
                    new_line^.next_line := NIL;
                    new_line^.line := blank_line (1, number_of_output_bytes);
                    new_line^.line (format_effector) := '+';
                    current_line := new_line;
                  ELSE
                    current_line := current_line^.next_line;
                  IFEND;
                WHILEND;
                current_line^.line (output_line_index) := input_line (input_line_index);
              IFEND;
            IFEND;
            output_line_index := output_line_index + 1;
            output_line_altered := TRUE;
          IFEND;
        CASEND;
        input_line_index := input_line_index + 1;
      WHILEND;

{ The limits of either the input buffer or the output buffer have been reached.
{ Handle the condition by writing the output buffer and/or reading new data.

      IF status.normal THEN
        IF output_line_index > number_of_output_bytes THEN
          write_output_lines (first_overstrike_line, output_file_byte_address, output_file_id, output_line,
                output_line_altered, output_line_count, number_of_output_bytes, status);
          IF NOT status.normal THEN
            RETURN;
          IFEND;

          output_line_index := first_text_column;

          IF input_file_position = amc$mid_record THEN

{ The data mode can not be transparent because the file would have an undefined
{ record structure and "mid-record" would be meainingless.  Assume the data mode
{ is coded, skip to the next record and refill the input buffer.

            amp$get_partial (input_file_id, ^input_line, maximum_input_bytes, ignored_record_size,
                  input_file_byte_count, input_file_byte_address, input_file_position, amc$skip_to_eor,
                  status);

            IF status.normal AND (input_file_position <> amc$eoi) THEN
              amp$get_next (input_file_id, ^input_line, maximum_input_bytes, input_file_byte_count,
                    input_file_byte_address, input_file_position, status);
            IFEND;
          ELSEIF input_file_position <> amc$eoi THEN
            IF (data_mode_value^.keyword_value (1, 5) = 'CODED') OR
                  (input_line_index > input_file_byte_count) THEN
              amp$get_next (input_file_id, ^input_line, maximum_input_bytes, input_file_byte_count,
                    input_file_byte_address, input_file_position, status);
              input_line_index := 1;
            IFEND;

            IF (data_mode_value^.keyword_value (1, 11) = 'TRANSPARENT') THEN

{ Search the input file for the next transparent end-of-line character.

              misc_index := input_line_index;
              search_character_found := FALSE;
              WHILE (NOT search_character_found) AND (input_file_position <> amc$eoi) DO
                WHILE (misc_index <= input_file_byte_count) AND (NOT search_character_found) DO
                  IF input_line (misc_index) = teol_character THEN
                    search_character_found := TRUE;
                  ELSE
                    misc_index := misc_index + 1;
                  IFEND;
                WHILEND;
                IF NOT search_character_found THEN
                  amp$get_next (input_file_id, ^input_line, maximum_input_bytes, input_file_byte_count,
                        input_file_byte_address, input_file_position, status);
                  misc_index := 1;
                IFEND;
              WHILEND;
              IF search_character_found THEN
                input_line (1, (input_file_byte_count - misc_index)) := input_line ((misc_index + 1), * );
                input_file_byte_count := (input_file_byte_count - misc_index);
              IFEND;
            IFEND; { IF data-mode = coded
          IFEND; { IF mid-record ELSE NOT end-of-file

{ At this point, the output buffer has been written, and the input buffer has
{ a fresh supply of data. Reset the index into the input line.

          input_line_index := 1;
        IFEND;

        IF (input_line_index > input_file_byte_count) AND (input_file_position <> amc$eoi) THEN
          IF input_file_position = amc$mid_record THEN
            amp$get_partial (input_file_id, ^input_line, maximum_input_bytes, ignored_record_size,
                  input_file_byte_count, input_file_byte_address, input_file_position, amc$no_skip, status);
          ELSE
            IF data_mode_value^.keyword_value (1, 5) = 'CODED' THEN
              write_output_lines (first_overstrike_line, output_file_byte_address, output_file_id,
                    output_line, output_line_altered, output_line_count, number_of_output_bytes, status);
              IF NOT status.normal THEN
                RETURN;
              IFEND;
              output_line_index := first_text_column;
            IFEND;

            amp$get_next (input_file_id, ^input_line, maximum_input_bytes, input_file_byte_count,
                  input_file_byte_address, input_file_position, status);
            input_line_index := 1;
          IFEND; { IF mid-record ELSE end-of-record

          input_line_index := 1;
        IFEND;
      IFEND; { IF status.normal
    WHILEND;

    IF status.normal THEN
      write_output_lines (first_overstrike_line, output_file_byte_address, output_file_id, output_line,
            output_line_altered, output_line_count, number_of_output_bytes, status);
    IFEND;
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF pvt [p$input].value^.field_values^ [file_field].value = NIL THEN
      jmp$close_output_file (input_file_id, local_status);
    ELSE
      fsp$close_file (input_file_id, local_status);
    IFEND;
    fsp$close_file (output_file_id, status);
    IF (NOT local_status.normal) AND status.normal THEN
      status := local_status;
    IFEND;

    IF status.normal THEN
      IF data_mode_value^.keyword_value (1, 11) = 'TRANSPARENT' THEN
        data_mode_value^.kind := clc$keyword;
        data_mode_value^.keyword_value := 'CODED';

        clp$change_variable (pvt [p$data_mode].variable^, data_mode_value, status);

      IFEND;
    IFEND;

  PROCEND nfp$emulate_format_effectors;
MODEND nfm$emulate_format_effectors;
