PROGRAM trimline;

{$e+}

 {Program to read a file, trim the rightmost columns, }
 {then trim trailing blanks, and then output into a }
 {second file. }


CONST
   version = '1.0';
   maxline = 255;    {longest line we can handle}

TYPE
   byte = 0..255;
   char12 = PACKED ARRAY [1..12] OF CHAR;

   STRING0 = STRING 0;
   STRING255 = STRING 255;
   line_string = STRING maxline;
   
VAR
   status   :INTEGER;
  
   flag        :BOOLEAN;
   trim_flag   :BOOLEAN;
   list_flag   :BOOLEAN;
   debug_flag  :BOOLEAN;


   inf_name   :char12;
   inf_file   :TEXT;  {input file variable}

   outf_name   :char12;
   outf_file   :TEXT;  {output file variable}
   rec_count, rec_thousands   :INTEGER;


   this_line   :line_string;
   
   trunc_length   :INTEGER;   {truncate lines to this length}

{-----------------------------------------------------------}
{-----------------------------------------------------------}
{-----------------------------------------------------------}

FUNCTION LENGTH ( str: STRING255) :INTEGER;  EXTERNAL;
FUNCTION INDEX  ( stra, strb :STRING255 ):INTEGER; EXTERNAL;
PROCEDURE SETLENGTH (VAR str :STRING0; len :INTEGER); EXTERNAL;

{-----------------------------------------------------------}


PROCEDURE trim_blanks  ( VAR this_line :line_string );
 
 {Trim trailing blanks }

VAR
   col   :INTEGER;
   flag   :BOOLEAN;

BEGIN{PROCEDURE}
   col := LENGTH (this_line);
   flag := FALSE;
   WHILE (col>0) AND (NOT flag) DO BEGIN
      IF this_line[col] = ' ' THEN BEGIN
         col := col - 1;
         END
      ELSE BEGIN
         flag := TRUE;
      END{IF};
   END{WHILE};

   SETLENGTH (this_line, col);

   IF debug_flag THEN BEGIN
      col := LENGTH (this_line);
      WRITELN ('%exit trim_blanks: length=', col:4);
      WRITELN (this_line);
   END{IF};

END{PROCEDURE};

{--------------------------------------------------------}

PROCEDURE truncate_line (VAR this_line :line_string);

VAR
   len   :INTEGER;

BEGIN{PROCEDURE}
   len := LENGTH (this_line);
   IF len > trunc_length THEN BEGIN
      SETLENGTH (this_line, trunc_length);
   END{IF};

   IF debug_flag THEN BEGIN
      len := LENGTH (this_line);
      WRITELN ('%exit trunc_line: length=', len:4);
      WRITELN (this_line);
   END{IF};

END{PROCEDURE};


{--------------------------------------------------------}


FUNCTION upper_case (in_char :CHAR) :CHAR;

BEGIN
   upper_case := in_char;
   IF in_char IN ['a'..'z'] THEN BEGIN
      upper_case := CHR( ORD(in_char) - 32 );
   END{IF};
END{FUNCTION};


{--------------------------------------------------------}
 
FUNCTION ask_yes_or_no  :BOOLEAN;

VAR
   flag   :BOOLEAN;
   response   :CHAR;
BEGIN{FUNCTION}
   flag := FALSE;
   WHILE NOT flag DO BEGIN
      WRITE ('(Y or N)');
      READLN(response);
      response := upper_case (response);
      IF (response='Y') OR (response='N') THEN BEGIN
         flag := TRUE;
         END
      ELSE BEGIN
         WRITELN('Try again. ');
      END{IF};
   END{WHILE};

   ask_yes_or_no :=  response='Y';
END{FUNCTION};


{--------------------------------------------------------}

FUNCTION get_open :INTEGER;

VAR
   result   :INTEGER;

BEGIN{FUNCTION};
   result := 0;

   WRITE ('Enter the input file name: ');
   READLN (inf_name);

   RESET (inf_name, inf_file);

   IF EOF(inf_file) THEN result := -1;

   get_open := result;
END{FUNCTION};


{--------------------------------------------------------}
 
FUNCTION get_close  :INTEGER;

BEGIN{FUNCTION}
   get_close := 0;
END{FUNCTION};


{--------------------------------------------------------}

FUNCTION get_line (VAR this_line :line_string) :INTEGER;

VAR
   result   :INTEGER;
   len    :INTEGER;

BEGIN{FUNCTION}
   result := 0;

   IF EOF(inf_file) THEN BEGIN
      result := -1;
      SETLENGTH (this_line, 0);
      END
   ELSE BEGIN

      READLN (inf_file, this_line);

      IF debug_flag THEN BEGIN
         len := LENGTH (this_line);
         WRITELN ('Input line: status=', result:4, 
                  '  length=', len:3);
         WRITELN (this_line);
      END{IF};
   END{IF};

   get_line := result;
END{FUNCTION};


{--------------------------------------------------------}

FUNCTION put_open :INTEGER;

VAR
   result   :INTEGER;

BEGIN{FUNCTION};
   result := 0;

   WRITE ('Enter the output file name: ');
   READLN (outf_name);

   REWRITE (outf_name, outf_file);

   rec_count := 0;
   rec_thousands := 0;
 
   put_open := result;
END{FUNCTION};


{-----------------------------------------------------------}

FUNCTION put_close :INTEGER;

VAR
   result   :INTEGER;

BEGIN{FUNCTION}
   result := 0;

   WRITELN (rec_thousands:4, ',', rec_count:3,
            ' output records in file ', outf_name );
   
   put_close := result;
END{FUNCTION};


{--------------------------------------------------------}

FUNCTION put_line (VAR this_line :line_string ) :INTEGER;

VAR
   result   :INTEGER;
   len      :INTEGER;

BEGIN{FUNCTION}
   result := 0;

   IF list_flag and debug_flag THEN BEGIN
      len := LENGTH (this_line);
      WRITE (len:2, ' ');
   END{IF};

   IF list_flag THEN WRITELN (this_line );
   WRITELN (outf_file, this_line );

   rec_count := rec_count + 1;
   IF rec_count >= 1000 THEN BEGIN
      rec_thousands := rec_thousands + 1;
      rec_count := 0;
   END{IF};

   put_line := result;
END{FUNCTION};



{-------------------------------------------------------}
{-------------------------------------------------------}
{-------------------------------------------------------}

BEGIN{PROGRAM}
   WRITELN
   ('Trim File Program  Version ', version);

   WRITELN ('This program reads an input file, trims the ');
   WRITELN ('last N columns from the lines, then trims any');
   WRITELN ('trailing blanks,');
   WRITELN ('and writes lines into output file.');

   WRITE('Debugging on? ');
   debug_flag := ask_yes_or_no;
   IF debug_flag THEN WRITELN('Debug is on.');

   WRITE('List the lines as they are read? ');
   list_flag := ask_yes_or_no;

   flag := FALSE;
   WHILE NOT flag DO BEGIN
      WRITE ('Enter column# to which we will truncate: ');
      READLN (trunc_length);
      IF (trunc_length < 1)  OR  (trunc_length > 255) THEN BEGIN
         WRITELN ('*** Too small or too big.  Try again.');
         END
      ELSE BEGIN
         WRITELN ('Lines longer than ', trunc_length:3,
                   ' will be truncated.');
         flag := TRUE;
      END{IF};
   END{WHILE};

   WRITE('Trim trailing blanks from output lines? ');
   trim_flag := ask_yes_or_no;

   status := get_open;
   IF status <> 0 THEN WRITELN ('Cannot open input file.');

   IF status=0 THEN BEGIN
      status := put_open;
      IF status <>0 THEN WRITELN ('Cannot open output file.');
   END{IF};

   IF status=0 THEN BEGIN
      WHILE status = 0  DO BEGIN
         status := get_line (this_line);
      
         IF status = 0 THEN BEGIN
            truncate_line (this_line);
            IF trim_flag THEN trim_blanks (this_line);
            status := put_line (this_line);
         END{IF};
      END{WHILE};
   END{IF};

   status := get_close;
   status := put_close;

   WRITELN('End of Trim');

END{PROGRAM}
.

