home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / ada / tutorial / ada_tutr.ada < prev    next >
Text File  |  1991-03-25  |  26KB  |  518 lines

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