home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Guide / c-cplusplus-interactive-guide.iso / c_ref / csource4 / 262_01 / cmenu.txt < prev    next >
Text File  |  1988-03-30  |  12KB  |  300 lines

  1. .ce 2
  2. Help for Those Really Long Dumb Menu Programs
  3. by Robert Ramey
  4.  
  5. I just got my Hewlett Packard Laser Jet II.  It seems to have
  6. everything.  All I have to do is read the manual so I can
  7. set up the correct printer control codes.  This machine has a zillon
  8. options, all with funny codes and rules about which combinations
  9. of codes and options are valid.
  10. If I want to avoid a lot of tedious work sifting through manual
  11. everytime I want to change the printer setup,  I'll have to
  12. write a program.  Since I'm a programmer I don't mind
  13. This is an application made to order for a series of menus.
  14. Now if you've written one menu driven program you've written
  15. them all.  Or at least it seems that way.  This is another
  16. tedious job.  Its still better than sifting through the printer
  17. manual all the time as its only done once.  However,  writing
  18. a menu driven program is tedious in itself.
  19.  
  20. I decided that this was the last tedious menu program I was going
  21. to write.
  22.  
  23. 1. Table Driven Code.
  24.  
  25. My solution is to write once a small piece of code which
  26. handles dialog with the operator using a table of menus as a
  27. guide.  Then for each new menu application all I have to
  28. write are the menus themselves and some "action routines"
  29. which are invoked when certain points in the menu dialog are
  30. touched.
  31.  
  32. Listing 1 shows the menus used for my laser printer program.
  33. The labels place each menu in its proper place in the hierarchy.
  34. At any time the operator can respond with one of the menu
  35. selections, return, or escape.
  36. Generally, escape will end the menu sequence. Return will return
  37. to the previous menu, and a valid menu selection will display
  38. a sub menu.
  39. For example, the top menu is the first to be displayed.
  40. If the operator selects 2 the menu labeled 2 is displayed.
  41. If the operator then selects 1 the menu labeled 21 is displayed.
  42.  
  43. This flow of control will end if a menu selection has no sub
  44. menu or a specific "action routine" is specified.
  45. In this example,  For menu
  46. selection "4. Just exit" I have chosen exit(0) as the action
  47. routine.  When this selection is chosen function exit() will
  48. be called with argument 0.
  49. If there is no sub menu nor is there any specific "action routine"
  50. a function action() will be called with a character pointer argument.
  51. This argument contains the sequence of responses that led to the
  52. current position in the hierarchy.
  53.  
  54. The basic idea of this program is that the operator moves around
  55. the hierarchy of menus at will.
  56. Listing 2 shows an example of the laser printer program in action.
  57.  
  58. Listing 3 shows how my laser printer setup program functions with
  59. the menus.  The main program calls the library function menu()
  60. then exits.  The program doesn't specify the flow of control.
  61. This was specified in the menus.
  62. Later I'll show the code for menu() along with
  63. how the menus get into the program itself.
  64. Now the only thing left is to code the action routines.
  65. As the operator makes selections from the menus below selection
  66. "2. Alter print setup", function action() is executed.  This records
  67. his choices in the array p.
  68. From time to time he may select
  69. option "1. Display current printer setup" to see which combination
  70. he has selected so far and to check that is valid.
  71. This will invoke the function display().
  72. When he is satisfied, he selects "3. Write printer control codes
  73. and exit".  The finish() function is then executed which writes
  74. the proper codes to the output file.
  75.  
  76. Separating the menus and flow of control from the
  77. action routines makes writing a program
  78. much more like writing a suite of small almost independent
  79. programs.  It also makes it much easier to expand the program:
  80. All one must do is add on to menus and the action routines.
  81. The rest of the program need not be touched.
  82.  
  83. 2. How It Works
  84.  
  85. Each menu is stored in a data structure like that shown in listing 4.
  86. To initiate a menu dialog the main program calls menu() with the
  87. address of the initial menu as the parameter.
  88.  
  89. Listing 5 shows the menu() function.  menu() displays the menu
  90. whose address it has recieved as an argument a : character for
  91. a prompt and waits for a response.  When a response is recieved
  92. it is compared against the first character in each line of the
  93. menu.  If it matches, the corresponding action routine is called
  94. with its associated parameter.  A hierarchy of menus is implemented
  95. by specifying menu() as the action routine with the address of the
  96. sub menu as the parameter.
  97.  
  98. When an action routine (including menu()) returns,  it should specify
  99. which of the previously displayed menus should be repeated.
  100. If it returns a value of 0, the immediatly previous menu will be
  101. repeated.  If it returns a value of 1, the menu two levels back
  102. will be repeated, etc.
  103. In our laser printer setup program example, the function copies()
  104. returns a value of 0 so that the "What do you want to change" menu
  105. will be repeated.  The function action() returns 1 so that
  106. menus such as
  107.  
  108.     Choose One.
  109.     1. Portrait(vertical)
  110.     2. Landscape(horizontal)
  111.  
  112. will not be repeated immediatly after a choice is made.
  113. When ever the operator responds to a menu with RETURN, menu()
  114. returns a value of 0 which repeats the previous menu.
  115. Whenever the operator responds with ESCAPE, menu()
  116. returns a value of 99 which will normally return through all the menus
  117. back to the initial menu() call.
  118.  
  119. Listing 6 show the C code which implements the menus originally
  120. displayed in Listing 1.  This should help to clarify the functioning
  121. of the menu() function as well as the the laser printer setup
  122. program.  To summarize,  A table driven menu program consists of
  123. three separatly compiled modules:
  124.  
  125. .in +4
  126. A set of action routines along with a main program which calls menu(&m)
  127.  
  128. A set of menu data structures containing the text of the menus,
  129. action routine addresses and paramters
  130.  
  131. A library function menu()
  132. .in -4
  133.  
  134. On my system, the laser printer setup program is produced by the
  135. following commands:
  136.  
  137.     cc slptrm
  138.     cc slptr
  139.     zlink slptr,slptrm,crunlib/
  140.  
  141. 3. Polishing Up the System.
  142.  
  143. So far we have simplfied the preparation of menu driven programs
  144. by separating the menus from the program code.
  145. Now we are now left with
  146. the task of coding the original menu into a C data structure.
  147. This is almost as bad as coding the menus into the original program.
  148. However, the job of translating the menus in listing 1 to the
  149. C program module in listing 6 is completely mechanical.  It can
  150. be turned over to a program we might call a menu compiler.
  151.  
  152. Listing 7 shows the program cmenu.c.  This programs reads a file
  153. in the format of list 1 and writes a file in the format of listing 6.
  154. If the menu in figure 1 is in a file named slptrm.mnu, the new
  155. command sequence is:
  156.  
  157.     cmenu <a:slptrm.mnu >slptrm.c
  158.     cc slptrm
  159.     cc slptr
  160.     zlink slptr,slptrm,crunlib/
  161.  
  162. Each menu in the input file to menu compiler should be in the
  163. following format:
  164.  
  165. .in +4
  166. The menu index indicating its position in the hierarchy
  167. should start in column 1.
  168.  
  169. Subsequent lines should start with tab.
  170.  
  171. The menu question on one or more lines.
  172.  
  173. The menu selections one per line.  Menu selections are
  174. distinguished by a '.' in the second character
  175. position of the text.
  176. .in -4
  177.  
  178. Each menu selection may be followed by a ';' and an action routine
  179. and parameter.  If no action routine is specified, the menu
  180. compiler will fill in a default action routine and parameter.
  181. If the menu indices indicate that a sub menu exists, the
  182. default action routine is menu() and the default parameter is
  183. the address of the submenu.  If there exists no sub menu,
  184. the default action routine is action() and the default parameter
  185. is a pointer to a string which contains the menu responses which
  186. brought us to this point.
  187.  
  188. Sometimes I want to insert an action routine within the
  189. hierarchy of menus.  For example, consider the following
  190. menu and code fragment from a modem transfer program:
  191.  
  192. .nf
  193.     ...
  194.     4. send file;gfname(m4)
  195.     ...
  196. 4
  197.     Which prototcal do you want to use?
  198.     1. XMODEM with check sum
  199.     2. XMODEM with crc
  200.     3. YMODEM
  201.     4. Kermit
  202.