Previous | Next | Table of Contents | Index | Program List | Copyright

9.4 Problem Solving: Operating System Redirection of Standard Files

Many popular operating systems, including UNIX and MS-DOS, have a feature that allows the standard input and output files--normally the keyboard and screen, respectively--to be "redirected" or temporarily reassigned to disk files. This feature, which is independent of Ada or any other programming language, allows you, for example, to tell a program that normally gets its input interactively to get it instead from a given file. Similarly, a program that normally writes its output to the screen can be told to put all that output in a file instead. In UNIX or MS-DOS, if you have an Ada program called MyProg, say, which uses keyboard Get calls, executing the operating system-level command

   MyProg < FileOne.dat
causes MyProg to take all its standard input from FileOne.dat instead of the keyboard. (This assumes that FileOne.dat has been created and filled with data.) Executing the command
    MyProg < FileOne.dat > FileTwo.dat
causes the program, without any change in its source code, to read its input from FileOne.dat and write its output to FileTwo.dat. This is a handy technique, used in writing many operating system commands. It doesn't work well if the program is highly interactive, with a lot of prompting, because the prompts go to the output file while the input comes from the input file, untouched by human hands! The next case study will show a program that does not prompt but uses keyboard Get calls; its input data can be entered either from the keyboard or by redirection.


Case Study: A Histogram-Plotting Program

Researchers in linguistics or cryptography (the study of secret codes) are often interested in the frequency of occurrence of the various letters in a section of text. A particularly useful way to summarize the number of occurrences is the histogram or bar graph, in which a bar is drawn for each letter, the length of the bar corresponding to the relative frequency of occurrence.

PROBLEM SPECIFICATION

Write a program which draws a histogram for the frequency of occurrence of the letters of the alphabet. Uppercase and lowercase letters are to be counted separately; nonletter characters can be ignored.

ANALYSIS

This program is a variation of the concordance program, Program 8.13, developed in Section 8.9. Instead of getting input as a single line from the terminal, this program will read a text file by using input redirection, compute the number of occurrences of each of the 52 (lower- and uppercase) letters, and draw an appropriately tall vertical bar on the screen for each of the 52 letters. A sample screen dump, produced by running the program with its own source file used as input, is shown in Figure 9.2.

Figure 9.2
Output from Histogram Program for Its Own Source File

              Scale: 1 star = 10 occurrences

       *
       *
       *
       *
       *
       *
       *              *
       *            * *
   *   *         *  * *
   *   *         *  * *
   *   *  *      *  * *
   * * *  *     **  * *
   * * *  **    **  ***        *
   * * *  **    **  ***        *
   * * *  **  * **  ****       * *   *    **
   * ***  **  * *** ****       * *   *  * **   **
   * ***  **  ***** **** **  * * *  **  * *** ***  *
   *********  ***** ******** ****** **  ***** **** *
   ****************************************************
   abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

DESIGN

Algorithm

The initial algorithm for this program is

1. Initialize all letter counters to 0.

2. Read the input file character by character. For each character that is a letter, increment the appropriate letter counter.

3. Plot the results on the screen.

We leave it to the student to fill in the algorithm refinements and to develop a test plan.

IMPLEMENTATION

Program 9.4 gives the program for this case study.

Program 9.4
Histogram Plotting Program

WITH Ada.Text_IO;
WITH Ada.Integer_Text_IO;
WITH Screen;
PROCEDURE Histogram IS
------------------------------------------------------------------------
--| Plots a histogram on the screen consisting of vertical bars.
--| Each bar represents the frequency of occurrence of a given
--| alphabet letter in the input file.
--| The input file is assumed to be Standard_Input; 
--| use input redirection if you wish to use a disk file instead.
--| Author: Michael B. Feldman, The George Washington University 
--| Last Modified: November 1995                                     
--|                                                              
------------------------------------------------------------------------
  
  SUBTYPE UpperCase IS Character RANGE 'A'..'Z';
  SUBTYPE LowerCase IS Character RANGE 'a'..'z';
  TYPE Occurrences IS ARRAY(Character RANGE <>) OF integer;
  Uppers   : Occurrences(UpperCase);
  Lowers   : Occurrences(LowerCase);

  NextCh   : Character;
  Scale    : Natural;
  MaxCount : Natural := 0;
  WhichCol : Screen.Width;
 

  PROCEDURE Plot(WhichCol  : Screen.Width; 
                 BottomRow : Screen.Depth;
                 HowMany   : Screen.Depth; 
                 WhichChar : Character) IS

  -- draws one vertical bar on the screen
  -- Pre: WhichCol, BottomRow, HowMany, and WhichChar are defined
  -- Post: draws a bar in column WhichCol, using character WhichChar
  --       to do the plotting. The bottom of the bar is given by
  --       BottomRow; the bar contains HowMany characters.

  BEGIN -- Plot

    FOR Count IN 0 .. Howmany - 1 LOOP

      Screen.MoveCursor(Column => WhichCol, Row => BottomRow - Count);
      Ada.Text_IO.Put(Item => WhichChar);

    END LOOP;

  END Plot;
 
BEGIN -- Histogram

  -- initialize letter-counter arrays
  Uppers := (OTHERS => 0);
  Lowers := (OTHERS => 0);

  -- read each character in the file; update letter counters
  WHILE NOT Ada.Text_IO.End_Of_File LOOP
    WHILE NOT Ada.Text_IO.End_Of_Line LOOP

      Ada.Text_IO.Get(NextCh);
      CASE NextCh IS
        WHEN UpperCase =>
          Uppers(NextCh) := Uppers(NextCh) + 1;
          IF Uppers(NextCh) > MaxCount THEN
            MaxCount := Uppers(NextCh);
          END IF;
        WHEN LowerCase =>
          Lowers(NextCh) := Lowers(NextCh) + 1;
          IF Lowers(NextCh) > MaxCount THEN
            MaxCount := Lowers(NextCh);
          END IF;
        WHEN OTHERS =>
          NULL;
      END CASE;

    END LOOP;
    Ada.Text_IO.Skip_Line;
  END LOOP;
 
  Scale := MaxCount / 20 + 1;
 
  Screen.ClearScreen;
  Screen.MoveCursor(Row => 1, Column => 15);
  Ada.Text_IO.Put(Item => "Scale: 1 star = ");
  Ada.Integer_Text_IO.Put(Item => Scale, Width => 1);
  Ada.Text_IO.Put(Item => " occurrences");
  Screen.MoveCursor(Row => 22, Column => 4);
  Ada.Text_IO.Put
    (Item => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
  WhichCol := 4;

  FOR C IN LowerCase LOOP

    IF Lowers(C) /= 0 THEN
      Plot(WhichCol, 21, Lowers(C) / scale + 1, '*');
    END IF;
    WhichCol := WhichCol + 1;

  END LOOP;

  FOR C IN UpperCase LOOP

    IF Uppers(C) /= 0 THEN
      Plot(WhichCol, 21, Uppers(C) / scale + 1, '*');
    END IF;
    WhichCol := WhichCol + 1;

  END LOOP;

  Screen.MoveCursor(Row => 24, Column => 1);
  
END Histogram;

Procedure Plot takes care of plotting the vertical bars on the screen, from bottom to top. Its parameters are the column in which the bar is desired, the bottom row of the column, the height of the column, and the character to be used for plotting the bar. Screen.MoveCursor is used to move the cursor from the bottom of the column to the top, plotting a character at each point.

The main program counts the occurrences of each letter as was done in the concordance program ( Program 8.13), with one essential difference: A record must be kept of the maximum number of occurrences. This is done because a column can be no more than 20 rows high, so the height of the columns must be scaled to the maximum. For example, if no letter occurs more than 60 times in the file, a 20-row column corresponds to approximately 60 occurrences. Each dot in the column then corresponds roughly to 3 occurrences of that letter; the number of occurrences of each letter, then, is divided by 3 to get the height of the column; 1 is added so that if there are any occurrences at all of a given letter, that column will be at least 1 row tall.

Exercises for Section 9.4

Programming

  1. Rewrite Copy_File ( Program 9.3) so that redirection is used to get the names of the input and output files.


Previous | Next | Table of Contents | Index | Program List | Copyright

Copyright © 1996 by Addison-Wesley Publishing Company, Inc.