/*
**++
**  FACILITY:
**	NEWSMENU.C
**
**  ABSTRACT:
**	This module contains the code and data needed to run the menus system.
**
**  AUTHOR:
**	Geoffrey Weatherall
**      University of Waikato
**      Hamilton
**      NEW ZEALAND
**
**  COPYRIGHT:
**	Copyright (c) 1991, with the same conditions as for the rest of the
**                        NEWS system.
**
**  MODIFICATION HISTORY:
**  Version History:
**   V6.0 4    Jan 1991 initial
**   V6.1    3-Feb-1992	rankin@eql.caltech.edu
**    - port to gcc
**   V6.1B1 15-Aug-1992 rankin@eql.caltech.edu
**    - clean up braces in initialization of menu structure
**   6.1b8  24-Jan-1994  Mark Martinec  mark.martinec@ijs.si
**    - replace calls to smg$put_chars with calls to smg_put_chars 
**    - check status returned from all calls to SMG$
**   V6.1b11 14-Apr-1997	Mark Martinec   mark.martinec@ijs.si
**    - replace call to strcat with safer strnncat
**--
**/

#ifdef vaxc
#module NEWSMENU "V6.2"
#endif

#define _NEWSMENU_C
#define module_name "NEWSMENU"

#include "newsinclude.h"
#include "newsextern.h"

#include "newsmenu.h"


/* the definitions below are returned by run_menu to get_menu_input when a
   special condition occurs - such as user abort or display scrolling at
   level 3 (news_context).
 */
#define level_3_up -3
#define level_3_down -4
#define level_3_page_up -5
#define level_3_page_down -6
/*********************************************************************************
 *
 * Constants
 *
 * MAX_TEXT - the max number of characters in a menu option
 * MAX_COMMAND - the max number of characters in a command
 * MAX_ITEMS - the maximum number of option/items in a menu ie 7 1 2
 * MAX_MENUS - the maximum number of menus
 * KEY_RIGHT_ARROW - key to move menu highlighter right
 * KEY_LEFT_ARROW - key to move menu highlighter left
 * KEY_RETURN - key that selects option highlighter is on
 * KEY_ABORT - key that aborts menu
 * KEY_HELP - help that gets help
 * KEY_PAGE_UP - key that pages display up
 * KEY_PAGE_DOWN - key that pages display down
 * KEY_UP_ARROW - key that move display up one line
 * KEY_DOWN_ARROW - key that moves display down one line
 *
 ******************************************************************************/

#define MAX_TEXT 20
#define MAX_COMMAND 40
#define MAX_ITEMS 9
#define MAX_MENUS 30
#define KEY_RIGHT_ARROW SMG$K_TRM_RIGHT
#define KEY_LEFT_ARROW SMG$K_TRM_LEFT
#define KEY_RETURN SMG$K_TRM_CR
#define KEY_ABORT SMG$K_TRM_F11
#define KEY_HELP SMG$K_TRM_HELP
#define KEY_PAGE_UP SMG$K_TRM_PREV_SCREEN
#define KEY_PAGE_DOWN SMG$K_TRM_NEXT_SCREEN
#define KEY_UP_ARROW SMG$K_TRM_UP
#define KEY_DOWN_ARROW SMG$K_TRM_DOWN



int my_pb;  /* the display used my the menu */
int menu_rows = 2; /* number of rows in the display */

/*
 * The user may wish to scroll and item up and down while reading it after
 * having started a menu.  In order to scroll an item and keep the menu
 * active the menu must temporarily return control to the code in the
 * module "NEWSDISPLAY", and after "NEWSDISPLAY" has scrolled the item
 * the menu must restart.  The paragraph below describes how this is done.
 *
 * First the current menu and the option within the menu are stored in
 * saved_menu and saved option.  Then the pasteboard batching level is
 * restored.  The the "auto_restart" flag is set true.  Then the command
 * which will cause the scrolling is returned to "NEWSDISPLAY" which does
 * the scrolling.  Then instead of the next command being read in the menu
 * is restarted and the current menu and option are restore, and the
 * "auto_restart" flag is cleared.
 */
int saved_option, saved_menu;
int auto_restart = 0;

typedef struct {
                char text_of_option[ MAX_TEXT ]; /* text of an option */
                int  start_possition;            /* not user setable */
                unsigned  quick_key_value;       /* ascii of quick key */
                int  quick_key_possition;        /* offset in text */
                char resultant_command[ MAX_COMMAND ];/* option's command */
                int  next_menu;                  /* option's submenu */
                char assistance_text[80];        /* help the user */
               } MENU_ITEM;

typedef struct {
                int       number_of_options;    /* options in this menu */
                MENU_ITEM option[ MAX_ITEMS ];  /* array of options */
               } A_MENU;



      /* over the next few pages all the menus are stored in an array */

A_MENU menu[ MAX_MENUS ] ={ /* menus are numbered 0 .. MAX_MENU-1 */
/*
    Text    Leave Quick-Key Quick-Offset  Command Text      Next Menu
------------------------------------------------------------------------------*/

{ /* first menu at newsgroup level        MENU 0 */
 8 , {
  { {"New"}       , 0 , 'n'     , 0 ,     {"READ/NEW"} ,            -1 ,
           {"Read the next unread item, beginning in the newsgroup pointed to"} },
  { {"Items"}     , 0 , 'i'     , 0 ,     {"DIR/ITEMS"} ,           -1 ,
           {"See the list of items in the newsgroup pointed to"} },
  { {"Dir"}       , 0 , 'd'     , 0 ,     {""} ,                     3 ,
           {"Select the type of directory to be shown {}"} },
  { {"enRolment"} , 0 , 'r'     , 2 ,     {""} ,                     4 ,
           {"Join or leave the newsgroup pointed to {}"} },
  { {"Post"}      , 0 , 'p'     , 0 ,     {"POST"} ,                -1 ,
           {"Add a item to the newgroup pointed to"} },
  { {"preVious"}  , 0 , 'v'     , 3 ,     {"READ/PREVIOUS"} ,       -1 ,
           {"Re-read the last item read"} },
  { {"Exit"}      , 0 , 'e'     , 0 ,     {"EXIT"} ,                -1 ,
           {"Finishing using NEWS"} },
  { {"Other"}     , 0 , 'o'     , 0 ,     {""} ,                     6 ,
           {"Various other commands {}"} },
 }
}, /* end - first menu at newsgroup level */



{  /* first menu when at level 2 ie item list       MENU 1 */
 8 , {
  { {"New"}       , 0 , 'n'     , 0 ,     {"READ/NEW"} ,            -1 ,
           {"Read the next unread item below the pointer"} },
  { {"Read"}      , 0 , 'r'     , 0 ,     {""} ,                     7 ,
           {"Select a reading command {}"} },
  { {"Stream"}    , 0 , 's'     , 0 ,     {""} ,                    15 ,
           {"Follow the current conversation stream forwards or backwards {}"} },
  { {"Add"}       , 0 , 'a'     , 0 ,     {""} ,                     9 ,
           {"Add a item to the current newsgroup {}"} },
  { {"sKip"}      , 0 , 'k'     , 1 ,     {""} ,                    10 ,
           {"Skip some items {}"} },
  { {"Newsgroups"}, 0 , 'g'     , 4 ,     {"NEWSGROUPS"} ,          -1 ,
           {"See the list of newsgroups"} },
  { {"Exit"}      , 0 , 'e'     , 0 ,     {"EXIT"} ,                -1 ,
           {"Finish using NEWS"} },
  { {"Other"}     , 0 , 'o'     , 0 ,     {""} ,                    11 ,
           {"Select other commands such as edit a file or quit {}"} },
 }
},  /* first menu at level two     */



{  /* first menu when at level three, ie reading an item     MENU 2 */
 9 , {
  { {"New"}       , 0 , 'n'     , 0 ,     {"READ/NEW"} ,            -1 ,
           {"Read the next unread item"} },
  { {"neXt"}      , 0 , 'x'     , 2 ,     {"READ/NEXT"} ,           -1 ,
           {"Skip the rest of this item and begin reading the next"} },
  { {"Move"}      , 0 , 'm'     , 0 ,     {""} ,                    14 ,
           {"Move around in the current item {}"} },
  { {"Read"}      , 0 , 'r'     , 0 ,     {""} ,                    13 ,
           {"Select a type of read {}"} },
  { {"Stream"}    , 0 , 's'     , 0 ,     {""} ,                    15 ,
           {"Follow the current conversation stream forwards or backwards {}"} },
  { {"Add"}       , 0 , 'a'     , 0 ,     {""} ,                     9 ,
           {"Add a item to the current newsgroup {}"} },
  { {"Items"}     , 0 , 'i'     , 0 ,     {"DIR/ITEMS"} ,           -1 ,
           {"See the list of items in this newsgroup"} },
  { {"newsGroups"}, 0 , 'g'     , 4 ,     {"NEWSGROUPS"} ,          -1 ,
           {"See the list of newsgroups"} },
  { {"Other"}     , 0 , 'o'     , 0 ,     {""} ,                    16 ,
           {"Select a command not listed here {}"} },
 }
},  /* first menu at level three    */



{  /* directory type     MENU 3 */
 3 , {
  { {"Registered"}, 0 , 'r'     , 0 ,     {"DIR/REGISTERED"} ,      -1 ,
           {"Show a directory of only the newsgroups you are registered in"} },
  { {"New"}       , 0 , 'n'     , 0 ,     {"DIR/NEW"} ,             -1 ,
           {"Show a directory of your registered newsgroups that have unread items"} },
  { {"All"}       , 0 , 'a'     , 0 ,     {"DIR/ALL"} ,             -1 ,
           {"Show a directory of all newsgroups"} },
 }
},  /*  directory type   */



{  /* enrollment action - register/deregister MENU 4 */
 2 , {
  { {"Register"}  , 0 , 'r'     , 0 ,     {"REGISTER"} ,            -1 ,
           {"Register in the current newsgroup"} },
  { {"Deregister"}, 0 , 'd'     , 0 ,     {"DEREGISTER"} ,          -1 ,
           {"Deregister from the current newsgroup"} },
 }
},  /* enrollment action    */



{  /* what to clear - marks || kill   MENU 5 */
 2 , {
  { {"Marks"}     , 0 , 'm'     , 0 ,     {"DELETE MARKER"} ,       -1 ,
           {"Remove all marks"} },
  { {"Filters"}   , 0 , 'f'     , 0 ,     {"CLEAR KILL"} ,          -1 ,
           {"Remove all filters skipping subjects and senders "} },
 }
},  /*  what to clear   */



{  /* other commands from level 1  MENU 6 */
 5 , {
  { {"Quit"}      , 0 , 'q'     , 0 ,     {"QUIT"} ,                -1 ,
           {"Finish using NEWS and do not keep a record of items read"} },
  { {"sHell"}     , 0 , 'h'     , 1 ,     {""} ,                    17 ,
           {"Temporarily return to $ prompt or edit a file {}"} },
  { {"Noscreen"}  , 0 , 'n'     , 0 ,     {"NOSCREEN"} ,            -1 ,
           {"Switch to scrolling screen mode; use SCREEN to return to current mode"} },
  { {"Clear"}     , 0 , 'c'     , 0 ,     {""} ,                     5 ,
           {"Clear kill filters or marks {}"} },
  { {"See"}       , 0 , 's'     , 0 ,     {""} ,                    18 ,
           {"See skip filters and marks {}"} },
 }
},  /** other commands from level 1     */



{  /* read options for level 2  MENU 7 */
 8 , {
  { {"Header"}    , 0 , 'h'     , 0 ,     {"READ/HEADER"} ,         -1,
           {"See the header of the item pointed to"} },
  { {"Previous"}  , 0 , 'p'     , 0 ,     {"READ/PREVIOUS"} ,       -1 ,
           {"See the last messages read"} },
  { {"Editor"}    , 0 , 'e'     , 0 ,     {"READ/EDITOR"} ,         -1 ,
           {"Place the item pointed to in an editor (so FIND etc can be used)"} },
  { {"Newest"}    , 0 , 'n'     , 0 ,     {"READ *"} ,              -1 ,
           {"Read the newest item in this newsgroup"} },
  { {"Last"}      , 0 , 'l'     , 0 ,     {"READ/LAST"} ,           -1 ,
           {"Read the item listed before the pointer"} },
  { {"Marked"}    , 0 , 'm'     , 0 ,     {"READ/MARKER"} ,         -1 ,
           {"Read the next marked item"} },
  { {"Decrypted"} , 0 , 'd'     , 0 ,     {"READ/ROT13"} ,          -1 ,
           {"Use the ROT13 method to decrypt the item pointed to"} },
  { {"Unread"}    , 0 , 'u'     , 0 ,     {"UNREAD"} ,              -1 ,
           {"Remove the record of having read the item pointed to"} },
 }
},  /* * read options for level 2    */



{  /* export options for level 2  MENU 8 */
 2 , {
  { {"Print"}     , 0 , 'p'     , 0 ,     {"PRINT/NOWAIT"} ,        -1 ,
           {"Print the current item on the system printers"} },
  { {"Extract"}   , 0 , 'e'     , 0 ,     {"EXTRACT"} ,             -1 ,
           {"Copies the current item into a file"} },
 }
},  /* * export options for level 2    */



{  /* add options for level 2      MENU 9 */
 3 , {
  { {"Followup"}  , 0 , 'f'     , 0 ,     {"FOLLOWUP/HEADERS"} ,    -1 ,
           {"Add an item to NEWS which is a comment about the current item"} },
  { {"Post"}      , 0 , 'p'     , 0 ,     {"POST/HEADER"} ,         -1 ,
           {"Add an item to NEWS"} },
  { {"Reply"}     , 0 , 'r'     , 0 ,     {"REPLY/HEADERS"} ,       -1 ,
           {"Send EMAIL to the author of the current item"} },
 }
},  /*  add options for level 2    */



{  /* skip options from level 2 MENU 10 */
 5 , {
  { {"Stream"}    , 0 , 's'     , 0 ,     {"SKIP/FOLLOWUP"} ,       -1 ,
           {"Skip all items in the current conversation stream"} },
  { {"To-current"}, 0 , 't'     , 0 ,     {"SKIP/POINTER"} ,        -1  ,
           {"Skip all items up to and including the current item"} },
  { {"suBject"}   , 0 , 'b'     , 2 ,     {"KILL/SUBJECT"} ,        -1 ,
           {"Filter out (Skip) all items with the same subject as the current item"} },
  { {"seNder"}    , 0 , 'n'     , 2 ,     {"KILL/FROM"} ,           -1 ,
           {"Filter out (Skip) all items sent by the sender of the current item"} },
  { {"Current"}   , 0 , 'c'     , 0 ,     {"SKIP"} ,                -1 ,
           {"Skip the current item"} },
 }
},  /* * skip options from level 2    */



{  /* others options from level 2       MENU 11 */
 6 , {
  { {"Clear"}     , 0 , 'c'     , 0 ,     {""} ,                    12 ,
           {"Remove kill filters or marks {}"} },
  { {"eXport"}    , 0 , 'x'     , 1 ,     {""} ,                     8 ,
           {"Print or extract the item pointed to {}"} },
  { {"Quit"}      , 0 , 'q'     , 0 ,     {"QUIT"} ,                -1 ,
           {"Finish using NEWS and do not keep a record of items read"} },
  { {"sHell"}     , 0 , 'h'     , 1 ,     {""} ,                    17 ,
           {"Temporarily return to $ prompt or edit a file {}"} },
  { {"Noscreen"}  , 0 , 'n'     , 0 ,     {"NOSCREEN"} ,            -1 ,
           {"Switch to scrolling screen mode; use SCREEN to return to current mode"} },
  { {"enRolment"} , 0 , 'r'     , 2 ,     {""} ,                     4 ,
           {"Register or deregister from this newsgroup {}"} },
 }
},  /* others options from level 2     */



{  /* what to clear from level 2 and three   MENU 12 */
 2 , {
  { {"Mark"}      , 0 , 'm'     , 0 ,     {"UNMARK"} ,              -1 ,
           {"Remove any marks on the current items"} },
  { {"Filters"}   , 0 , 'f'     , 0 ,     {"CLEAR KILL"} ,          -1 ,
           {"Remove all the filters skipping certain subjects and senders"} },
 }
},  /*  what to clear   */



{  /* read options for level 3  MENU 13 */
 8 , {
  { {"Header"}    , 0 , 'h'     , 0 ,     {"READ/HEADER"} ,         -1,
           {"See the header of this item"} },
  { {"Previous"}  , 0 , 'p'     , 0 ,     {"READ/PREVIOUS"} ,       -1 ,
           {"Re-read the last messages read"} },
  { {"Editor"}    , 0 , 'e'     , 0 ,     {"READ/EDITOR"} ,         -1 ,
           {"Place this item into an editor (so FIND etc can be used)"} },
  { {"Newest"}    , 0 , 'n'     , 0 ,     {"READ *"} ,              -1 ,
           {"Read the newest item in this newsgroup"} },
  { {"Last"}      , 0 , 'l'     , 0 ,     {"READ/LAST"} ,           -1 ,
           {"Read the item listed before the item being read"} },
  { {"Marked"}    , 0 , 'm'     , 0 ,     {"READ/MARKER"} ,         -1 ,
           {"Read the next marked item"} },
  { {"Decrypted"} , 0 , 'd'     , 0 ,     {"READ/ROT13"} ,          -1 ,
           {"Use the ROT13 method to decrypt this item"} },
  { {"Unread"}    , 0 , 'u'     , 0 ,     {"UNREAD"} ,              -1 ,
           {"Remove the record of having read this item"} },
 }
},  /* * read options for level 3    */



{                   /* move option at level 3 MENU 14 */
 4 , {
  { {"Down"}      , 0 , 'd'     , 0 ,     {"DOWN 18"} ,             -1 ,
           {"See the next page of this item (Same as NEXT SCREEN )"} },
  { {"Up"}        , 0 , 'u'     , 0 ,     {"UP 18"} ,               -1 ,
           {"See the previous page of this item (Same as PREV SCREEN)"} },
  { {"Top"}       , 0 , 't'     , 0 ,     {"TOP"} ,                 -1,
           {"See the first page of this item"} },
  { {"Bottom"}    , 0 , 'b'     , 0 ,     {"BOTTOM"} ,              -1,
           {"See the last page of this item"} },
 }
},  /* move options    */



{                   /* conversation stream following commands 3 MENU 15 */
 3 , {
  { {"Child"}     , 0 , 'c'     , 0 ,     {"READ/FOLLOWUP"} ,       -1 ,
{"Follow this conversation stream forward-read any comments on the current item"} },
  { {"Parent"}    , 0 , 'p'     , 0 ,     {"READ/PARENT"} ,         -1 ,
{"Follow this conversation stream backwards-read any items this item comments on"} },
  { {"Ancestor"}  , 0 , 'a'     , 0 ,     {"READ/TOPIC"} ,          -1 ,
{"See the start of this conversation stream-the oldest parent of the current item"} },
 }
},  /* read options for level 3    */



{  /* others options from level 2       MENU 16 */
 9 , {
  { {"Exit"}      , 0 , 'e'     , 0 ,     {"EXIT"} ,                -1 ,
           {"Finish using NEWS"} },
  { {"See"}       , 0 , 's'     , 0 ,     {""} ,                    18 ,
           {"See skip filters and marks {}"} },
  { {"Clear"}     , 0 , 'c'     , 0 ,     {""} ,                    12 ,
           {"Remove kill filters or marks {}"} },
  { {"eXport"}    , 0 , 'x'     , 1 ,     {""} ,                     8 ,
           {"Print or extract the item pointed to"} },
  { {"Quit"}      , 0 , 'q'     , 0 ,     {"QUIT"} ,                -1 ,
           {"Finish using NEWS and do not keep a record of items read"} },
  { {"sKip"}      , 0 , 'k'     , 1 ,     {""} ,                    10 ,
           {"Skip over some items {}"} },
  { {"Noscreen"}  , 0 , 'n'     , 0 ,     {"NOSCREEN"} ,            -1 ,
           {"Switch to scrolling screen mode; use SCREEN to return to current mode"} },
  { {"enRolment"} , 0 , 'r'     , 2 ,     {""} ,                     4 ,
           {"Register or deregister from this newsgroup {}"} },
  { {"sHell"}     , 0 , 'h'     , 1 ,     {""} ,                    17 ,
           {"Temporarly return to $ prompt or edit a file {}"} },
 }
},  /** others options from level 3     */




{  /* shell options  MENU 17 */
 2 , {
  { {"Edit"}      , 0 , 'e'     , 0 ,     {"EDIT"} ,                -1 ,
           {"Use the editor to create a file"} },
  { {"spaWn"}     , 0 , 'w'     , 3 ,     {"SPAWN"} ,               -1 ,
           {"*Temporarly return to the $ prompt; enter LOGOUT to return to NEWS"}, },
 }
},  /* shell options     */




{  /* see options  MENU 18 */
 2 , {
  { {"Filters"}   , 0  ,'f'     , 0 ,     {"SHOW KILL"} ,           -1 ,
           {"See any kill filters"} },
  { {"Marks"}     , 0  ,'m'     , 0 ,     {"SHOW MARK"} ,           -1 ,
           {"See any marks"} },
 }
},  /* see    */

} /* menus information */;

static int run_menu(A_MENU *);

/****************************************************************************
 *
 * Module - menu
 *
 */
#define menu_wrap  /* this make menus wrap from one end to the other */
/*#define menu_nowrap*/ /* this means the menu will not wrap */

/* NOTE: you must define EITHER menu_wrap OR menu_nowrap - but NOT both */




/*
 *  get_menu_input
 *
 *  Runs the menu system until either a command or "escape_option" can be
 *  returned.
 */
const char *get_menu_input(void)
{
int status;
int menu_to_run = -1;     /* index number of menu being run */
int option_selected = -1; /* option the user selected */

if (!(smg_active)) {  /* menus can not be run from noscreen mode */
  printf("Menus do not work in NOSCREEN mode.  To use menus return to SCREEN mode\n" );
  printf("by entering the command \"SCREEN\"\n");
  return( menu_escape_pressed );
  };
if (!auto_restart) {
  _c$cks(smg$erase_line(&my_pb, c$ac(1), c$ac(1)));  /* clear where menu will go */
  _c$cks(smg$erase_line(&my_pb, c$ac(2), c$ac(1)));
  _c$cks(smg$paste_virtual_display(&my_pb, &pid, c$rfi(devrow-1), c$ac(1)));
  };

if ( auto_restart ) menu_to_run = saved_menu;
                                                /* put menu display on screen*/
else if ( news_context == 1 ) menu_to_run = 0;       /* get number of initial menu*/
else if ( news_context == 2 ) menu_to_run = 1;       /* to run */
else if ( news_context == 3 ) menu_to_run = 2;

for (;;)  { /* run menus until either a command or abort selected */
  option_selected = run_menu( &menu[ menu_to_run ] ); /* run current menu */
  if ( option_selected == escape_option ) {           /* check for abort */
    _c$cks(smg$unpaste_virtual_display(&my_pb, &pid));
    _c$cks(smg$erase_line(&trailer_vd, c$ac(1), c$ac(5)));
    return( menu_escape_pressed );
    };
  if ( option_selected == level_3_up ) {
    _c$cks(smg$erase_line(&trailer_vd, c$ac(1), c$ac(5)));
    auto_restart = 1;
    saved_menu = menu_to_run;
    return( "up 1\0" );
    };
  if ( option_selected == level_3_page_up ) {
    _c$cks(smg$erase_line(&trailer_vd, c$ac(1), c$ac(5)));
    auto_restart = 1;
    saved_menu = menu_to_run;
    return( "up 18\0" );
    };
  if ( option_selected == level_3_page_down ) {
    _c$cks(smg$erase_line(&trailer_vd, c$ac(1), c$ac(5)));
    auto_restart = 1;
    saved_menu = menu_to_run;
    return( "down 18\0" );
    };
  if ( option_selected == level_3_down ) {
    _c$cks(smg$erase_line(&trailer_vd, c$ac(1), c$ac(5)));
    auto_restart = 1;
    saved_menu = menu_to_run;
    return( "down 1\0" );
    };
  if ( menu[menu_to_run].option[ option_selected ].next_menu == -1 ) {
        _c$cks(smg$unpaste_virtual_display( &my_pb , &pid )); /* no more menus to ..*/
        clear_err_line();                             /* run                */
        return(menu[menu_to_run].option[ option_selected ].resultant_command );
   };
  menu_to_run = menu[menu_to_run].option[ option_selected ].next_menu;
                                         /* get the index of the next menu */
 }; /* for */
 _c$cks(smg$set_cursor_abs(&trailer_vd, c$ac(1), c$ac(1)));
 _c$cks(smg$erase_line(&trailer_vd, c$ac(1), c$ac(5)));
 return( menu_escape_pressed );
}



/*
 *  run_menu
 *
 *  Runs one menu.  Terminates when an option is selected or abort key pressed.
 *  Returns either number of option selected, or a special terminator such as
 *  user abort or up, down, page up, page down (for level three).
 *
 */

static int run_menu ( to_be_drawn )
A_MENU *to_be_drawn;

 {
int status;
int col_count = 1;        /* keeps track of how far out when drawing up menu */
int option_count;         /* used to check quick keys of all options */
unsigned terminator = 0;  /* user's key press */
int levels_down = 0;      /* keeps track of SMG$ batching level */
int bolded,  reversed , normaled; /* attributes of screen characters */
int current_option = 0;   /* option that reverse bar is on */

bolded = SMG$M_BOLD;
reversed = SMG$M_REVERSE;
normaled = 0;

if ( !auto_restart ) {     /* if menu is not already on screen draw it */
  _c$cks(smg$erase_line(&my_pb, c$ac(1), c$ac(1))); /* clear space for menu */
  _c$cks(smg$erase_line(&my_pb, c$ac(2), c$ac(1)));

  for ( option_count =  0 ; option_count < to_be_drawn->number_of_options ; option_count++
) {
    smg_put_chars(my_pb,
	to_be_drawn->option[option_count].text_of_option,
	1, col_count, 0,0);
    to_be_drawn->option[ option_count].start_possition = col_count;
    _c$cks(smg$change_rendition(&my_pb, c$ac(1),
	c$rfi(col_count+to_be_drawn->option[option_count].quick_key_possition),
	c$ac(1), c$ac(1), &bolded));
    col_count += ( strlen(to_be_drawn->option[ option_count].text_of_option) + 1);
    };    /* draw up menu */
  }
else {  /* if menu already on screen then restart from same option */
  current_option = saved_option;
  auto_restart = 0;
  };
if (!( smg$end_pasteboard_update( &pid ) == SMG$_BATWASOFF ) ){
  ++levels_down;
  while(  smg$end_pasteboard_update( &pid )== SMG$_BATSTIPRO ) levels_down++;
  }; /* take off batching but remember level */


for (;;) {   /* main loop in running a menu */
  if (!( ( terminator == KEY_DOWN_ARROW ) ||   /* check if assistance text */
         ( terminator == KEY_UP_ARROW   ) ||   /* updating.  It does NOT   */
         ( terminator == KEY_PAGE_DOWN )  ||   /* user as move pointer.    */
         (terminator == KEY_PAGE_UP ) ) ) {
     _c$cks(smg$erase_line(&my_pb, c$ac(2), c$ac(1)));
     smg_put_chars(my_pb,
	to_be_drawn->option[current_option].assistance_text,
	2,1, 0,0);
     };
 /* { char temp[255];
  *sprintf( temp , "%u  ",terminator );
  * smg_put_chars(my_pb, temp, 2,1, 0,0);
  * };
  */
  _c$cks(smg$change_rendition(&my_pb, c$ac(1),
	c$rfi(to_be_drawn->option[current_option].start_possition), c$ac(1),
	c$rfi(strlen(to_be_drawn->option[current_option].text_of_option)),
	&reversed)); /* reverse video the current option */
  _c$cks(smg$read_keystroke(&kid, &terminator)); /* read user key press */
  if (!(  (terminator == KEY_DOWN_ARROW )
       || (terminator == KEY_UP_ARROW )
       || (terminator == KEY_PAGE_DOWN )
       || (terminator == KEY_PAGE_UP ) ) ) { /* remove reverse bar from old */
    _c$cks(smg$change_rendition(&my_pb , c$ac(1), /* option */
	c$rfi(to_be_drawn->option[current_option].start_possition), c$ac(1),
	c$rfi(strlen(to_be_drawn->option[current_option].text_of_option)),
	&normaled));
    _c$cks(smg$change_rendition(&my_pb, c$ac(1),
	c$rfi(to_be_drawn->option[current_option].start_possition +
		to_be_drawn->option[current_option].quick_key_possition),
	c$ac(1), c$ac(1), &bolded)); /* re-bold quick key */
   };

  for ( option_count = 0 ; /* check menu option's quick key to see if one has*/
        option_count < to_be_drawn->number_of_options ;/* been pressed */
        option_count++ ) {
    if ( to_be_drawn->option[ option_count ].quick_key_value == terminator ) {
      while (levels_down) {
        --levels_down;
        _c$cks(smg$begin_pasteboard_update( &pid ));
        };
      return( option_count ) ;
      };
  };
  if ( terminator == KEY_RIGHT_ARROW ) current_option += 1;
  if ( terminator == KEY_LEFT_ARROW ) current_option -= 1;

  if ( terminator == KEY_DOWN_ARROW ) {
    while (levels_down) {
      --levels_down;
      _c$cks(smg$begin_pasteboard_update( &pid ));
      };
    if ( news_context == 3 ) { /* level three is special case */
      saved_option = current_option;
      return( level_3_down );
      };
    _c$cks(smg$begin_pasteboard_update(&pid));
    do_parse("DOWN 1\0"); /* this command for levels 1 and 2 */
    _c$cks(smg$end_pasteboard_update(&pid));
    levels_down = 0;
    if (!( smg$end_pasteboard_update( &pid ) == SMG$_BATWASOFF ) ){
      ++levels_down;
      while(  smg$end_pasteboard_update( &pid )== SMG$_BATSTIPRO ) levels_down++;
      }; /* restore batching level */
    };

  if ( terminator == KEY_UP_ARROW ) {
    while (levels_down) {
      --levels_down;
      _c$cks(smg$begin_pasteboard_update( &pid ));
      };
    if ( news_context == 3 ) { /* level three is special case */
      saved_option = current_option;
      return( level_3_up );
      };
    _c$cks(smg$begin_pasteboard_update( &pid ));
    do_parse("UP 1\0"); /* this command for level 1 and 2 */
    _c$cks(smg$end_pasteboard_update( &pid ));
    levels_down = 0;
    if (!( smg$end_pasteboard_update( &pid ) == SMG$_BATWASOFF ) ){
      ++levels_down;
      while(  smg$end_pasteboard_update( &pid )== SMG$_BATSTIPRO ) levels_down++;
      };
    };

  if ( terminator == KEY_PAGE_DOWN ) {
    while (levels_down) {
      --levels_down;
      _c$cks(smg$begin_pasteboard_update( &pid ));
      };
    if ( news_context == 3 ) {
      saved_option = current_option;
      return( level_3_page_down );
      };
    _c$cks(smg$begin_pasteboard_update(&pid));
    do_parse("DOWN 18\0");
    _c$cks(smg$end_pasteboard_update(&pid));
    levels_down = 0;
    if (!( smg$end_pasteboard_update( &pid ) == SMG$_BATWASOFF ) ){
      ++levels_down;
      while(  smg$end_pasteboard_update( &pid )== SMG$_BATSTIPRO ) levels_down++;
      };
    };

  if ( terminator == KEY_HELP ) {
    char help_command[250];
    clear_err_line();
    _c$cks(smg$end_display_update( &trailer_vd ));
    strcpy(help_command, "HELP "); /* compose help command */
    strnncat(help_command,sizeof(help_command),-1,
             to_be_drawn->option[current_option].resultant_command, -1, 0);
    while (levels_down) {
      --levels_down;
      _c$cks(smg$begin_pasteboard_update( &pid ));
      };
    _c$cks(smg$begin_pasteboard_update(&pid)); /* restore batching level */
    do_parse( help_command ); /* execute help command */
    _c$cks(smg$end_pasteboard_update(&pid));
    smg_put_chars(trailer_vd, "NEWS> ", 1,1, 0,0); /*tidy*/
    _c$cks(smg$erase_line(&trailer_vd, c$ac(2), c$ac(1)));            /*screen*/
    _c$cks(smg$repaste_virtual_display(&trailer_vd, &pid, c$rfi(devrow - 2), c$ac(1)));
    _c$cks(smg$repaste_virtual_display(&my_pb, &pid, c$rfi(devrow - 1), c$ac(1)));
    levels_down = 0;
    if (!( smg$end_pasteboard_update( &pid ) == SMG$_BATWASOFF ) ){
      ++levels_down;
      while(  smg$end_pasteboard_update( &pid )== SMG$_BATSTIPRO ) levels_down++;
      };/* turn off batching */
    };

  if ( terminator == KEY_PAGE_UP ) {
    while (levels_down) {
    --levels_down;
    _c$cks(smg$begin_pasteboard_update( &pid ));
    }
    if ( news_context == 3 ) {
      saved_option = current_option;
      return( level_3_page_up );
      };
  _c$cks(smg$begin_pasteboard_update(&pid));
  do_parse("UP 18\0");
  _c$cks(smg$end_pasteboard_update(&pid));
  levels_down = 0;
  if (!( smg$end_pasteboard_update( &pid ) == SMG$_BATWASOFF ) ) {
    ++levels_down;
    while(  smg$end_pasteboard_update( &pid )== SMG$_BATSTIPRO ) levels_down++;
    };
  };

  if (terminator == KEY_ABORT ) { /* user wants to quit menu without making a*/
    while (levels_down) {         /* selection */
      --levels_down;
      _c$cks(smg$begin_pasteboard_update( &pid ));
      };
    return( escape_option ) ;
    };

  if (terminator == KEY_RETURN ) { /* user has made choice */
    while (levels_down) {
      --levels_down;
      _c$cks(smg$begin_pasteboard_update( &pid ));
      };
    return( current_option ) ;
    };


  if (current_option < 0 )
#ifdef menu_wrap
     current_option = to_be_drawn->number_of_options - 1; /* loop around */
#endif
#ifdef menu_nowrap
     current_option = 0; /* do not move bar past end */
#endif

  if (current_option >= to_be_drawn->number_of_options )
#ifdef menu_nowrap
     current_option = to_be_drawn->number_of_options - 1; /* stop at end */
#endif
#ifdef menu_wrap
     current_option = 0;  /* loop around */
#endif


  } /* for loop */
 return( escape_option ) ;
} /* function */



/* initialise_menu
 *
 * This function initialises the menus and displays a message announcing
 * their existence.
 *
 */
void initialise_menus(void)
{
  int status;

  _c$cks(smg$create_virtual_display(&(menu_rows), &devcol, &my_pb, 0, 0, 0));
  if (smg_active)
    smg_put_chars(trailer_vd," Waikato Menus - Press F11 at NEWS> prompt",
                             3,36, 0,0);
}



/* auto_restarting
 *
 * This function returns true if the menu will be automatically restarting
 * at level 3, false otherwise.
 *
 */

int auto_restarting(void)
{
  return auto_restart ? 1 : 0;
}
