home *** CD-ROM | disk | FTP | other *** search
/ Hall of Fame / HallofFameCDROM.cdr / prog1 / ada-tutr.lzh / ADA-TUTR.ADA < prev    next >
Encoding:
Text File  |  1988-12-21  |  24.3 KB  |  466 lines

  1. -- ADA-TUTR.ADA   Ver. 1.20   21-DEC-1988
  2. -- Copyright 1988 John J. Herro
  3. -- Software Innovations Technology
  4. -- 1083 Mandarin Drive NE, Palm Bay, FL 32905-4706   (407)951-0233
  5. --
  6. -- Before compiling this file, you must compile ONE of the following:
  7. --
  8. --    MERIDIAN.ADA  Recommended when using a PC with the Meridian AdaStarter or
  9. --                     AdaVantage compiler and the DOS Environment Library.
  10. --    UNIX.ADA      Recommended for UNIX based systems, if you can also
  11. --                     compile GET.C with a C compiler and link with Ada.
  12. --    VAX.ADA       Recommended when using VAX Ada.
  13. --    VANILLA.ADA   "Plain vanilla" version for all other systems.  Should work
  14. --                     with ANY standard Ada compiler.  On some systems,
  15. --                     VANILLA.ADA may require you to strike ENTER after each
  16. --                     response.  However, you don't have to strike ENTER with
  17. --                     recent versions of TeleGen Ada.
  18. --
  19. -- See the PRINT.ME file for more information on installing ADA-TUTR on other
  20. -- computers.
  21. --
  22. --
  23. -- Before Running ADA-TUTR on a PC:
  24. --
  25. -- ADA-TUTR uses ANSI escape sequences for highlighting, cursor positioning,
  26. -- reverse video, etc.  Before ADA-TUTR will work correctly on a PC, you must
  27. -- install the device driver ANSI.SYS.  To install ANSI.SYS, do the following:
  28. --
  29. -- 1.  If there's a file CONFIG.SYS in the root directory of the disk from
  30. --     which you boot, type it and look for a line saying "DEVICE=ANSI.SYS"
  31. --     (without the quotes), in either upper or lower case.  If that line isn't
  32. --     present, add it to CONFIG.SYS anywhere in the file, using an ordinary
  33. --     text editor or word processor in the non-document mode.  If there's no
  34. --     CONFIG.SYS file, create one containing the single line "DEVICE=ANSI.SYS"
  35. --     (without the quotes).
  36. --
  37. -- 2.  If there's no file ANSI.SYS in your root directory, copy ANSI.SYS from
  38. --     from your system distribution diskette to the root directory of the disk
  39. --     from which you boot.
  40. --
  41. -- 3.  Reboot the computer.  ADA-TUTR should then work correctly.
  42. --
  43.  
  44. -- Introduction:
  45. --
  46. -- ADA-TUTR provides interactive instruction in the Ada programming language,
  47. -- allowing you to learn at your own pace.  On a PC, it requires a hard disk.
  48. -- Access to an Ada compiler is helpful, but not required.  You can exit this
  49. -- program at any time by striking X, and later resume the session exactly
  50. -- where you left off.  If you have a color monitor, you can set the
  51. -- foreground, background, and border colors at any time by typing S.
  52. --
  53. -- ADA-TUTR presents a screenful of information at a time.  Screens are read
  54. -- in 64-byte blocks from the random access file ADA-TUTR.DAT, using DIRECT_IO.
  55. -- For most screens, ADA-TUTR waits for you to strike one character to
  56. -- determine which screen to show next.  Screens are numbered starting with
  57. -- 101; each screen has a three-digit number.  Screens 101 through 108 have
  58. -- special uses, as follows:
  59. --
  60. -- 101 - This screen is presented when you complete the Ada course.  It
  61. --       contains a congratulatory message.  After this screen is shown,
  62. --       control returns directly to the operating system; the program doesn't
  63. --       wait for you to strike a character.
  64. -- 102 - This screen is presented when you exit ADA-TUTR before completing the
  65. --       course.  After this screen is shown, control returns directly to the
  66. --       operating system; the program doesn't wait for you to strike a
  67. --       character.
  68. -- 103 - This screen is shown whenever you strike X.  It displays the number of
  69. --       the last screen shown and the approximate percentage through the
  70. --       course.  It then asks if you want to exit the program.  If you strike
  71. --       Y, screen 102 is shown and control returns to the operating system.
  72. --       If you type N, screen 108 is shown to provide a menu of further
  73. --       choices.  From screen 103, you can also strike M to see the main menu
  74. --       (screen 106).
  75. -- 104 - This is the opening screen.  It asks if you've used ADA-TUTR before.
  76. --       If you strike N, a welcome screen is presented and the course begins.
  77. --       If you strike Y, screen 107 is shown.
  78. -- 105 - This screen allows you to type the number of the next screen you want
  79. --       to see.  For this screen, instead of striking one character, you type
  80. --       a three-digit number and presses ENTER.  Any number from 104 through
  81. --       the largest screen number is accepted.
  82. -- 106 - This screen contains the main menu of topics covered in ADA-TUTR.
  83. --       When you select a main topic, an appropriate sub-menu is shown.
  84. -- 107 - This screen is shown when you say that you've used ADA-TUTR before.
  85. --       It says "Welcome back!" and provides a menu that lets you resume where
  86. --       you left off, go back to the last question or Outside Assignment, go
  87. --       to the main menu (screen 106), or go to any specified screen number
  88. --       (via screen 105).
  89. -- 108 - This screen is shown when you answer N to screen 103.  It provides a
  90. --       menu similar to screen 107, except that the first choice takes you
  91. --       back to the screen shown before you saw 103.  For example, if you
  92. --       strike X while viewing screen 300, you'll see screen 103.  If you then
  93. --       answer N, you'll see screen 108.  From 108 the first menu selection
  94. --       takes you back to 300.
  95. --
  96.  
  97. -- Format of the Data File:
  98. --
  99. -- ADA-TUTR.DAT is a random access file of 64-byte blocks.  The first block is
  100. -- referred to as block 1.  Bytes 2 through 4 of block 1 contain, in ASCII, the
  101. -- number of the welcome screen that's shown when you say that you haven't used
  102. -- ADA-TUTR before.  Bytes 6 through 8 contain the number of the highest screen
  103. -- in the course.  (Bytes 1 and 5 contain blanks.)
  104. --
  105. -- Data for the screens are stored starting in block 32.  Bytes 9 of block 1
  106. -- through the end of block 31 contain, in ASCII, the numbers of the starting
  107. -- blocks for each of the 494 possible screens (101 through 594).  Four bytes
  108. -- are allocated for each starting block number.  So that each number will have
  109. -- exactly four digits, 1000 is added to each block number.  For example, data
  110. -- for screen 101 starts at block 32, so "1032" is stored (in bytes 9 through
  111. -- 12 of block 1).  The next four bytes refer to screen 102, etc.  Not all 494
  112. -- possible screens exist.  For each unused screen, four blanks are stored.
  113. --
  114. -- The first 64-byte block of each screen is a "control block."  Thus, block 32
  115. -- of ADA-TUTR.DAT is the control block for screen 101.  This block is followed
  116. -- by enough 64-byte blocks to contain the text for that screen.  In the text,
  117. -- '{' represents a digit for the foreground color (ASCII character '0' =
  118. -- black, '7' = white), and '}' represents a digit for the background color.
  119. --
  120. -- The first two bytes of the control block contain, in ASCII, the number of
  121. -- text blocks that follow.  A constant 10 is added to this number so that it
  122. -- will always have exactly two digits.  The next two bytes contain, in ASCII,
  123. -- the number of significant text characters in the last 64-byte block, plus
  124. -- ten.  This number can range from 11 to 74.  For example, if a screen has 138
  125. -- characters, three text blocks will be needed, and the last block will have
  126. -- ten significant characters.  Thus, the first four bytes of the control block
  127. -- will contain "1320" in ASCII.
  128. --
  129. -- Bytes 5 through 61 of the control block contain a list of characters that
  130. -- you might strike after seeing this screen.  Each character is followed by
  131. -- the three-digit number of the next screen to be shown when that character is
  132. -- struck.  The list is terminated by $.  There is room for as many as 14
  133. -- characters and screen numbers, and the terminating $.  For example, in the
  134. -- control block for screen 104, bytes 5 through 13 might contain "Y107N120$".
  135. -- This means that, if you strike Y, screen 107 will be shown, and if you
  136. -- strikes N, screen 120 will be shown.  Striking any other character will
  137. -- simply cause a beep (except that X can always be typed to exit the program,
  138. -- S can always be typed to set colors, and CR will be ignored).  If the list
  139. -- of characters begins with '#', you are prompted to type the next screen
  140. -- number.  This feature is used in screen 105.
  141. --
  142. -- A "screen number" of 098 following a character means "go back to the last
  143. -- Outside Assignment," and 099 means "go back to the last question."  These
  144. -- special numbers are used in screens 107 and 108.  Number 100 means "go back
  145. -- to the previous screen seen."
  146. --
  147. -- Bytes 62 and 63 of the control block each contain '$'.  Byte 64 contains 'Q'
  148. -- if this screen contains a question, 'A' if this screen introduces an Outside
  149. -- Assignment, and '$' otherwise.
  150. --
  151. -- ADA-TUTR opens the Data File in IN_FILE mode for read-only access.
  152. --
  153.  
  154. -- Format of the User File:
  155. --
  156. -- The User File ADA-TUTR.USR initially doesn't exist.  It's created the first
  157. -- time ADA-TUTR is run.
  158. --
  159. -- ADA-TUTR.USR is a random access file containing one 64-byte block.  Bytes 2
  160. -- through 4 contain, in ASCII, the number of the last screen read the last
  161. -- time you ran ADA-TUTR.  Byte 6 contains a digit for the foreground color you
  162. -- select, byte 8 contains a digit for the background color, and byte 10
  163. -- contains a digit for the border color.  All other bytes contain blanks.  The
  164. -- ASCII characters '0' through '7' represent black, red, green, yellow, blue,
  165. -- magenta, cyan, and white, in that order.  Note that not all color PCs have a
  166. -- separate border color.  ADA-TUTR.USR is a random access file so that it can
  167. -- be easily updated by Ada.  It contains 64 bytes so that it can be accessed
  168. -- with the same package, namely RANDOM_IO, that accesses the Data File.
  169. --
  170. -- If the User File exists, ADA-TUTR opens it in INOUT_FILE mode for read/write
  171. -- access.  If it doesn't exist, ADA-TUTR creates it.
  172. --
  173.  
  174. with CUSTOM_IO, DIRECT_IO; use CUSTOM_IO;
  175. procedure ADA_TUTR is
  176.    subtype BLOCK_SUBTYPE is STRING(1 .. 64);
  177.    package RANDOM_IO is new DIRECT_IO(BLOCK_SUBTYPE); use RANDOM_IO;
  178.    DATA_FILE        : FILE_TYPE;       -- The file from which screens are read.
  179.    USER_FILE        : FILE_TYPE;     -- Remembers last screen seen, and colors.
  180.    BLOCK            : BLOCK_SUBTYPE;          -- Data written to the User File.
  181.    CONTROL_BLOCK    : BLOCK_SUBTYPE;   -- Control info. for the current screen.
  182.    SN, OLD_SN       : INTEGER := 104;   -- Screen num. and previous screen num.
  183.    QUITTING_SN      : INTEGER := 104;      -- Screen number where you left off.
  184.    HIGHEST_SCREEN   : INTEGER;          -- Highest screen number in the course.
  185.    WELCOME_SCREEN   : INTEGER;                    -- Screen shown to new users.
  186.    INDX             : STRING(1 .. 1984);     -- Starting block numbers, + 1000.
  187.    FILES_OK         : BOOLEAN := FALSE;   -- True when files open successfully.
  188.    LEGAL_NOTE       : constant STRING := " Copyright 1988 John J. Herro ";
  189.                          -- LEGAL_NOTE isn't used by the program, but it causes
  190.                          -- the compiler to place this string in the .EXE file.
  191.    procedure OPEN_DATA_FILE is separate;
  192.    procedure OPEN_USER_FILE is separate;
  193.    procedure SHOW_CURRENT_SCREEN is separate;
  194.    procedure GET_NEXT_SCREEN_NUMBER is separate;
  195. begin
  196.    OPEN_DATA_FILE;
  197.    OPEN_USER_FILE;
  198.    if FILES_OK then
  199.       SET_BORDER_COLOR(TO => BORDER_COLOR);              -- Set default colors.
  200.       PUT(NORMAL_COLORS);
  201.       while SN > 0 loop          -- "Screen number" of 0 means end the program.
  202.          PUT(CLEAR_SCRN);                                  -- Clear the screen.
  203.          SHOW_CURRENT_SCREEN;
  204.          GET_NEXT_SCREEN_NUMBER;
  205.       end loop;
  206.       BLOCK := (others => ' ');       -- Write user-specific data to user file.
  207.       BLOCK(1 .. 4) := INTEGER'IMAGE(QUITTING_SN);
  208.       BLOCK(6)  := FORE_COLOR_DIGIT;
  209.       BLOCK(8)  := BACK_COLOR_DIGIT;
  210.       BLOCK(10) := CHARACTER'VAL(COLOR'POS(BORDER_COLOR) + 48);
  211.       WRITE(USER_FILE, ITEM => BLOCK, TO => 1);
  212.       CLOSE(DATA_FILE);
  213.       CLOSE(USER_FILE);
  214.    end if;
  215. end ADA_TUTR;
  216.  
  217. separate (ADA_TUTR)
  218. procedure OPEN_DATA_FILE is
  219.    DATA_FILE_NAME : constant STRING := "ADA-TUTR.DAT";
  220.    BLOCK          : BLOCK_SUBTYPE;  -- A 64-byte block of input from Data File.
  221. begin
  222.    OPEN(DATA_FILE, MODE => IN_FILE, NAME => DATA_FILE_NAME);
  223.    for I in 1 .. 31 loop                -- Read list of starting block numbers.
  224.       READ(DATA_FILE, ITEM => BLOCK, FROM => COUNT(I));
  225.       INDX(64*I - 63 .. 64*I) := BLOCK;
  226.    end loop;
  227.    WELCOME_SCREEN := INTEGER'VALUE(INDX(2 .. 4));
  228.    HIGHEST_SCREEN := INTEGER'VALUE(INDX(6 .. 8));
  229.    FILES_OK := TRUE;
  230. exception
  231.    when NAME_ERROR =>
  232.       PUT("I'm sorry.  The file " & DATA_FILE_NAME);
  233.       PUT_LINE(" seems to be missing.");
  234.    when others =>
  235.       PUT("I'm sorry.  The file " & DATA_FILE_NAME);
  236.       PUT_LINE(" seems to have the wrong form.");
  237. end OPEN_DATA_FILE;
  238.  
  239. separate (ADA_TUTR)
  240. procedure OPEN_USER_FILE is
  241.    USER_FILE_NAME : constant STRING := "ADA-TUTR.USR";
  242.    BLOCK          : BLOCK_SUBTYPE;  -- A 64-byte block of input from User File.
  243. begin
  244.    OPEN(USER_FILE, MODE => INOUT_FILE, NAME => USER_FILE_NAME);
  245.    READ(USER_FILE, ITEM => BLOCK, FROM => 1);
  246.    QUITTING_SN      := INTEGER'VALUE(BLOCK(1 .. 4));
  247.    OLD_SN           := QUITTING_SN;
  248.    FOREGRND_COLOR   := COLOR'VAL(INTEGER'VALUE(BLOCK(5 .. 6)));
  249.    BACKGRND_COLOR   := COLOR'VAL(INTEGER'VALUE(BLOCK(7 .. 8)));
  250.    BORDER_COLOR     := COLOR'VAL(INTEGER'VALUE(BLOCK(9 .. 10)));
  251.    FORE_COLOR_DIGIT := BLOCK(6);
  252.    BACK_COLOR_DIGIT := BLOCK(8);
  253.    NORMAL_COLORS(6) := FORE_COLOR_DIGIT;
  254.    NORMAL_COLORS(9) := BACK_COLOR_DIGIT;
  255. exception
  256.    when NAME_ERROR =>
  257.       begin
  258.          CREATE(USER_FILE, MODE => INOUT_FILE, NAME => USER_FILE_NAME);
  259.       exception
  260.          when others =>
  261.             PUT("I'm sorry.  I couldn't find or create ");
  262.             PUT_LINE(USER_FILE_NAME);
  263.             FILES_OK := FALSE;
  264.       end;
  265.    when others =>
  266.       PUT_LINE("I'm sorry.  The file " & USER_FILE_NAME & " seems to have");
  267.       PUT_LINE("the wrong form or contain bad data.");
  268.       PUT_LINE("You might want to delete the file and try again.");
  269.       PUT_LINE("(Default values will be used.)");
  270.       FILES_OK := FALSE;
  271. end OPEN_USER_FILE;
  272.  
  273. separate (ADA_TUTR)
  274. procedure SHOW_CURRENT_SCREEN is
  275.    NUM_OF_BLOCKS  : INTEGER;         -- Num. of blocks of text for this screen.
  276.    LAST_BLOCK_LEN : INTEGER;       -- Num. of significant chars. in last block.
  277.    HALF_DIFF      : INTEGER := (HIGHEST_SCREEN - WELCOME_SCREEN) / 2;
  278.    PERCENT        : INTEGER := (50 * (OLD_SN - WELCOME_SCREEN)) / HALF_DIFF;
  279.                           -- Percentage of the course completed.  Using 50 and
  280.                           -- HALF_DIFF guarantees that the numerator < 2 ** 15.
  281.    BLOCK          : BLOCK_SUBTYPE;  -- A 64-byte block of input from Data File.
  282.    WHERE          : INTEGER;         -- Location of control block in Data File.
  283. begin
  284.    WHERE := INTEGER'VALUE(INDX(SN*4 - 395 .. SN*4 - 392)) - 1000;
  285.                                  -- Get location of control block in Data File.
  286.    READ(DATA_FILE, ITEM => CONTROL_BLOCK, FROM => COUNT(WHERE));
  287.    NUM_OF_BLOCKS  := INTEGER'VALUE(CONTROL_BLOCK(1 .. 2)) - 10;
  288.    LAST_BLOCK_LEN := INTEGER'VALUE(CONTROL_BLOCK(3 .. 4)) - 10;
  289.    for I in 1 .. NUM_OF_BLOCKS loop
  290.       READ(DATA_FILE, ITEM => BLOCK, FROM => COUNT(WHERE + I));
  291.       ---------------------------------------------------------------
  292.       --  NOTE:  If screen 103 is redesigned, the slices in the    --
  293.       --  following IF block will have to be changed accordingly.  --
  294.       ---------------------------------------------------------------
  295.       if SN = 103 and I = 1 then    -- Screen 103 needs previous screen number.
  296.          BLOCK(58 .. 61) := INTEGER'IMAGE(OLD_SN);
  297.       elsif SN = 103 and I = 2 then       -- Screen 103 also needs % completed.
  298.          case PERCENT is
  299.             when INTEGER'FIRST..0 => BLOCK(34 .. 35) := " 0";
  300.             when 1 .. 9           => BLOCK(34 .. 35) := INTEGER'IMAGE(PERCENT);
  301.             when 10 .. 99         => BLOCK(33 .. 35) := INTEGER'IMAGE(PERCENT);
  302.             when others           => BLOCK(34 .. 35) := "99";
  303.          end case;
  304.       end if;
  305.       for J in BLOCK'RANGE loop
  306.          if BLOCK(J) = '{' then
  307.             BLOCK(J) := FORE_COLOR_DIGIT;
  308.          elsif BLOCK(J) = '}' then
  309.             BLOCK(J) := BACK_COLOR_DIGIT;
  310.          end if;
  311.       end loop;
  312.       if I = NUM_OF_BLOCKS then
  313.          PUT(BLOCK(1 .. LAST_BLOCK_LEN));
  314.       else
  315.          PUT(BLOCK);
  316.       end if;
  317.    end loop;
  318. end SHOW_CURRENT_SCREEN;
  319.  
  320. separate (ADA_TUTR)
  321. procedure GET_NEXT_SCREEN_NUMBER is
  322.    INPUT     : STRING(1 .. 4);                  -- Screen number that you type.
  323.    LEN       : INTEGER;                            -- Length of typed response.
  324.    VALID     : BOOLEAN;                   -- True when typed response is valid.
  325.    procedure SET_COLORS is separate;
  326.    procedure INPUT_ONE_KEYSTROKE is separate;
  327. begin
  328.    if SN = 103 then                    -- Screen 103 means you typed X to exit.
  329.       QUITTING_SN := OLD_SN;
  330.    elsif SN >= WELCOME_SCREEN then          -- Save SN so you can return to it.
  331.       OLD_SN := SN;
  332.    end if;
  333.    if SN < 103 then                          -- Set SN to # of the next screen.
  334.       SN := 0;      -- Set signal to end the program after screens 101 and 102.
  335.    elsif CONTROL_BLOCK(5) = '#' then        -- You type the next screen number.
  336.       VALID := FALSE;
  337.       while not VALID loop              -- Keep trying until response is valid.
  338.          PUT("# ");                                -- Prompt for screen number.
  339.          INPUT := "    ";  GET_LINE(INPUT, LEN);        -- Input screen number.
  340.          if INPUT(1) = 'x' or INPUT(1) = 'X' or INPUT(1) = ASCII.ETX then
  341.             SN := 103;                        -- Show screen 103 if you type X.
  342.             VALID := TRUE;                            -- X is a valid response.
  343.          elsif INPUT(1) = 's' or INPUT(1) = 'S' then
  344.             SET_COLORS;                            -- Set colors if you type S.
  345.             VALID := TRUE;                            -- S is a valid response.
  346.          else
  347.             begin                                    -- Convert ASCII input to
  348.                SN := INTEGER'VALUE(INPUT);           -- integer.  If in range,
  349.                VALID := SN in 104 .. HIGHEST_SCREEN; -- set VALID to TRUE.  If
  350.             exception                                -- it can't be converted
  351.                when others => null;                  -- (e.g., illegal char.),
  352.             end;                                     -- or it's out of range,
  353.          end if;                                     -- leave VALID = FALSE so
  354.          if not VALID and LEN > 0 then               -- so you can try again.
  355.             PUT_LINE("Incorrect number.  Please try again.");
  356.          end if;
  357.       end loop;
  358.    else
  359.       INPUT_ONE_KEYSTROKE;
  360.    end if;
  361. end GET_NEXT_SCREEN_NUMBER;
  362.  
  363. separate (ADA_TUTR.GET_NEXT_SCREEN_NUMBER)
  364. procedure SET_COLORS is
  365.    BRIGHT    : constant STRING := ASCII.ESC & "[1m";  -- Causes high intensity.
  366.    KEYSTROKE : CHARACTER := 'f';             -- Single character that you type.
  367.    SPACE     : constant STRING(1 .. 23) := (others => ' ');
  368. begin
  369.    while KEYSTROKE = 'f' or KEYSTROKE = 'b' or KEYSTROKE = 'r' or
  370.          KEYSTROKE = 'F' or KEYSTROKE = 'B' or KEYSTROKE = 'R' loop
  371.       PUT(CLEAR_SCRN);                                     -- Clear the screen.
  372.       NEW_LINE;
  373.       PUT(SPACE & "The " & BRIGHT & "foreground" & NORMAL_COLORS);
  374.       PUT_LINE(" color is now " & COLOR'IMAGE(FOREGRND_COLOR) & '.');
  375.       PUT(SPACE & "The " & BRIGHT & "background" & NORMAL_COLORS);
  376.       PUT_LINE(" color is now " & COLOR'IMAGE(BACKGRND_COLOR) & '.');
  377.       PUT(SPACE & "The " & BRIGHT & "  border  " & NORMAL_COLORS);
  378.       PUT_LINE(" color is now " & COLOR'IMAGE(BORDER_COLOR) & '.');
  379.       NEW_LINE;
  380.       PUT_LINE(SPACE & " Note:  Some color PCs don't have");
  381.       PUT_LINE(SPACE & "     separate border colors.");
  382.       NEW_LINE;
  383.       PUT_LINE(SPACE & "             Strike:");
  384.       PUT_LINE(SPACE & "F to change the foreground color,");
  385.       PUT_LINE(SPACE & "B to change the background color,");
  386.       PUT_LINE(SPACE & "R to change the   border   color.");
  387.       NEW_LINE;
  388.       PUT_LINE(SPACE & "Strike any other key to continue.");
  389.       GET(KEYSTROKE);                       -- Get one character from keyboard.
  390.       if KEYSTROKE = 'f' or KEYSTROKE = 'F' then
  391.          FOREGRND_COLOR := COLOR'VAL((COLOR'POS(FOREGRND_COLOR) + 1) mod 8);
  392.          if FOREGRND_COLOR = BACKGRND_COLOR then
  393.             FOREGRND_COLOR := COLOR'VAL((COLOR'POS(FOREGRND_COLOR) + 1) mod 8);
  394.          end if;
  395.       elsif KEYSTROKE = 'b' or KEYSTROKE = 'B' then
  396.          BACKGRND_COLOR := COLOR'VAL((COLOR'POS(BACKGRND_COLOR) + 1) mod 8);
  397.          if FOREGRND_COLOR = BACKGRND_COLOR then
  398.             BACKGRND_COLOR := COLOR'VAL((COLOR'POS(BACKGRND_COLOR) + 1) mod 8);
  399.          end if;
  400.       elsif KEYSTROKE = 'r' or KEYSTROKE = 'R' then
  401.          BORDER_COLOR := COLOR'VAL((COLOR'POS(BORDER_COLOR) + 1) mod 8);
  402.       end if;
  403.       FORE_COLOR_DIGIT := CHARACTER'VAL(48 + COLOR'POS(FOREGRND_COLOR));
  404.       BACK_COLOR_DIGIT := CHARACTER'VAL(48 + COLOR'POS(BACKGRND_COLOR));
  405.       NORMAL_COLORS(6) := FORE_COLOR_DIGIT;
  406.       NORMAL_COLORS(9) := BACK_COLOR_DIGIT;
  407.       PUT(NORMAL_COLORS);
  408.       SET_BORDER_COLOR(TO => BORDER_COLOR);
  409.    end loop;
  410. end SET_COLORS;
  411.  
  412. separate (ADA_TUTR.GET_NEXT_SCREEN_NUMBER)
  413. procedure INPUT_ONE_KEYSTROKE is
  414.    BLINK     : constant STRING := ASCII.ESC & "[5m";
  415.    KEYSTROKE : CHARACTER;                    -- Single character that you type.
  416.    PLACE     : INTEGER;                  -- Index to search list of characters.
  417.    VALID     : BOOLEAN := FALSE;          -- True when typed response is valid.
  418.    WHERE     : INTEGER;              -- Location of control block in Data File.
  419.    SEARCH    : CHARACTER;    -- 'A' = last Outside Assignment; 'Q' = last Ques.
  420. begin
  421.    PUT(">");                                       -- Prompt for one character.
  422.    while not VALID loop                 -- Keep trying until response is valid.
  423.       GET(KEYSTROKE);                       -- Get one character from keyboard.
  424.       if KEYSTROKE in 'a' .. 'z' then          -- Force upper case to simplify.
  425.          KEYSTROKE := CHARACTER'VAL(CHARACTER'POS(KEYSTROKE) - 32);
  426.       end if;
  427.       if KEYSTROKE = 'X' or KEYSTROKE = ASCII.ETX then
  428.          SN := 103;                           -- Show screen 103 if you type X.
  429.          VALID := TRUE;                               -- X is a valid response.
  430.       elsif KEYSTROKE = 'S' then
  431.          SET_COLORS;                               -- Set colors if you type S.
  432.          VALID := TRUE;                               -- S is a valid response.
  433.       end if;
  434.       PLACE := 5;           -- Search list of valid characters for this screen.
  435.       while not VALID and CONTROL_BLOCK(PLACE) /= '$' loop  -- $ ends the list.
  436.          if KEYSTROKE = CONTROL_BLOCK(PLACE) then
  437.                  -- Typed char. found in list; get screen # from control block.
  438.             SN := INTEGER'VALUE(CONTROL_BLOCK(PLACE + 1 .. PLACE + 3));
  439.             VALID := TRUE;   -- Characters in the list are all valid responses.
  440.          end if;
  441.          PLACE := PLACE + 4;    -- A 3-digit number follows each char. in list.
  442.       end loop;
  443.       if not VALID and KEYSTROKE /= ASCII.CR then        -- Beep if response is
  444.          PUT(ASCII.BEL);                                 -- not valid, but
  445.       end if;                                            -- ignore CRs quietly.
  446.    end loop;
  447.    if SN = 98 then                       -- Go back to last Outside Assignment.
  448.       PUT(BLINK & " Working..." & NORMAL_COLORS);
  449.       SEARCH := 'A';
  450.    elsif SN = 99 then                              -- Go back to last question.
  451.       SEARCH := 'Q';
  452.    elsif SN = 100 then                      -- Go back to the last screen seen.
  453.       SN := QUITTING_SN;
  454.    end if;
  455.    if SN = 98 or SN = 99 then
  456.       SN := OLD_SN;
  457.       CONTROL_BLOCK(64) := ' ';
  458.       while SN > WELCOME_SCREEN and CONTROL_BLOCK(64) /= SEARCH loop
  459.          SN := SN - 1;
  460.          WHERE := INTEGER'VALUE(INDX(SN*4 - 395 .. SN*4 - 392)) - 1000;
  461.                                  -- Get location of control block in Data File.
  462.          READ(DATA_FILE, ITEM => CONTROL_BLOCK, FROM => COUNT(WHERE));
  463.       end loop;
  464.    end if;
  465. end INPUT_ONE_KEYSTROKE;
  466.