home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume11 / menu_mh / part01 / dumb_menu.y < prev    next >
Encoding:
Lex Description  |  1990-03-10  |  11.6 KB  |  614 lines

  1. %{
  2. /* @(#)dumb_menu.y    1.3 90/03/08 */
  3.  
  4. static char *cpy_str =
  5.   "Copyright (c), Mike Howard, 1990, all rights reserved";
  6.  
  7. /* Conditions of use:
  8.  
  9.    This software is not for sale and is not to be sold by or
  10.    to anyone.
  11.  
  12.    You may use this software and may distribute it to anyone
  13.    you wish to provided you distribute the entire distribution
  14.    package w/o any deletions (i.e. include all the source code).
  15.  
  16.    I do not warrent this software to do anything at all and
  17.    am not responsible for anything which happens as a result of
  18.    its use.
  19. */
  20.  
  21. #include <stdio.h>
  22. #include <fcntl.h>
  23. #include <string.h>
  24. #include <signal.h>
  25. #include <setjmp.h>
  26.  
  27. struct parm {
  28.   struct parm *next;
  29.   char *prompt;
  30.   char *identifier;
  31.   char *value;
  32. };
  33.  
  34. struct item {
  35.   struct item *next;
  36.   char *prompt;
  37.   char *command;
  38.   struct parm *parms;
  39. };
  40.  
  41. struct item *menu_head;
  42. struct item *menu_tail;
  43.  
  44. int max_item;
  45.  
  46. struct parm *parm_list;
  47.  
  48. char *menu_title;
  49.  
  50. char *malloc();
  51. char *realloc();
  52.  
  53. int lex_errors;
  54. int yacc_errors;
  55. int line_number;
  56.  
  57. /* flags */
  58. int clear_flag;
  59. int bold_flag;
  60. int always_display_menu_flag;
  61.  
  62. /* Menus begin with a title definition
  63.    title { text for the title }
  64.  
  65.    This is followed by one or more menu-item definitions of the form:
  66.  
  67.    item { prompt } { shell command }
  68.    parm "name" { prompt }
  69.    parm "name" { prompt }
  70.    ;
  71.  
  72.    the crud in between braces may contain any character, including
  73.    escapped braces and back-slash (\).
  74.    The crud in between the double quotes may ONLY contain letters, digits,
  75.    and underscores;
  76.  
  77.    Sub-menus are formed by running dumb_menu as the shell process, pointed
  78.    to an appropriate sub-menu definition file.
  79.  
  80.    There is no provision for menus which require more than one screen 
  81.    to display.
  82. */
  83.  
  84. #define DEBUG0(fmt)    if(debug_mode>1)printf(fmt);
  85. #define DEBUG1(fmt,aa)    if(debug_mode>1)printf(fmt,aa);
  86. #define DEBUG2(fmt,aa,bb)    if(debug_mode>1)printf(fmt,aa,bb);
  87. #define DEBUG3(fmt,aa,bb,cc)    if(debug_mode>1)printf(fmt,aa,bb,cc);
  88.  
  89. %}
  90.  
  91. %union {
  92.   int ival;
  93.   char *txt;
  94.   char chr;
  95.   double dbl;
  96.   struct item *itm;
  97.   struct parm *prm;
  98. }
  99.  
  100. %token <ival> NUMBER
  101. %token <dbl> FLOAT
  102. %token <txt> TEXT PARM_NAME
  103. %token PARM ITEM TITLE ERROR
  104. %token CLEAR BOLD ALWAYS_SHOW
  105.  
  106. %type <itm> menu item
  107. %type <prm> parm
  108.  
  109. %%
  110.  
  111. menu : title menu_flags item
  112.     {
  113.       menu_head =
  114.         menu_tail = $3;
  115.       DEBUG1("Initial Menu Item:\n %s\n", $3->prompt);
  116.     }
  117.     | menu item
  118.     {
  119.       menu_tail->next = $2;
  120.       menu_tail = $2;
  121.       DEBUG1("Additional Menu Item:\n %s\n", $2->prompt);
  122.     }
  123.     ;
  124.  
  125. title : TITLE TEXT
  126.     {
  127.       menu_title = $2;
  128.       DEBUG1("menu title '%s'\n", $2);
  129.     }
  130.     ;
  131.  
  132. menu_flags :
  133.     | menu_flags menu_flag
  134.     ;
  135.  
  136. menu_flag : CLEAR
  137.     {
  138.       clear_flag++;
  139.     }
  140.     | BOLD
  141.     {
  142.       bold_flag++;
  143.     }
  144.     | ALWAYS_SHOW
  145.     {
  146.       always_display_menu_flag++;
  147.     }
  148.     ;
  149.  
  150. item : ITEM  TEXT  TEXT  parms ';'
  151.     {
  152.       $$ = make_new_item($2, $3, parm_list);
  153.       parm_list = (struct parm *)0;
  154.     }
  155.     ;
  156.  
  157. parms : /* empty */
  158.     | parms parm
  159.     ;
  160.  
  161. parm : PARM PARM_NAME TEXT
  162.     {
  163.       $$ = make_new_parm($2, $3);
  164.       $$->next = parm_list;
  165.       parm_list = $$;
  166.       DEBUG2("parm: %s\n'%s'\n", $2, $3);
  167.     }
  168.     ;
  169.  
  170. %%
  171.  
  172. char *use_msg = "usage: %s [-h | option(s) ]\n";
  173.  
  174. extern char *optarg;
  175. extern int optind, opterr;
  176. int tty_in;
  177. FILE *tty_file;
  178. int argcc;
  179. char **argvv;
  180. char *progname;
  181. char *in_fname = "stdin";
  182. char *menu_fname = "./menu.def";
  183. char *shell_path = "/bin/sh";
  184. char *cat_path = "/bin/cat";
  185. char *cmd_path;
  186. char *cmd_name;
  187.  
  188. struct item *selected_item;
  189. struct parm *selected_parms;
  190. FILE *tmp_file;
  191. char *tmp_fname;
  192.  
  193. int verbose;
  194. int debug_mode;
  195.  
  196. char *hlp[] = {
  197. "Option     Function",
  198. "-m file    set menu-definition file name to 'file' (menu.def)",
  199. "-s path    path to shell to execute scripts",
  200. "-c path    path to 'cat' for simple debug mode",
  201. "-v         make command execution verbose (via set -xv)",
  202. "-D         increment debug mode",
  203. (char *)0};
  204.  
  205. int display_menu_flag = 1;
  206. jmp_buf env;
  207. #define SIGS_FOR_JMP   1
  208. #define SIGS_FOR_CHILD 2
  209.  
  210. main(argc, argv)
  211. int argc;
  212. char **argv;
  213. {
  214.   int item_idx;
  215.  
  216.   init(argc, argv);
  217.  
  218.   if (yyparse())
  219.     fatal("Parse Error");
  220.  
  221.   if (lex_errors || yacc_errors)
  222.     fatal("corrupt menu definition");
  223.  
  224.   if (debug_mode) {
  225.     item_idx = 1;
  226.     for (selected_item=menu_head;selected_item;
  227.      selected_item = selected_item->next) {
  228.       printf("%2d. %s\n", item_idx++, selected_item->prompt);
  229.       printf("%s\n", selected_item->command);
  230.       for (selected_parms=selected_item->parms;selected_parms;
  231.        selected_parms = selected_parms->next)
  232.     printf("%s: '%s'\n", selected_parms->prompt,
  233.            selected_parms->identifier);
  234.     }
  235.   }
  236.  
  237.   init_terminal();
  238.  
  239.   do_menu();
  240. }
  241.  
  242. init(argc, argv)
  243. int argc;
  244. char **argv;
  245. {
  246.   int i;
  247.   int c;
  248.   extern char *optarg;
  249.   extern int optind, opterr;
  250.  
  251.   while ((c = getopt(argc, argv, "hcsm:vD")) != EOF) {
  252.     switch (c) {
  253.     case 'h':
  254.       for (i=0;hlp[i];i++)
  255.     printf("%s\n", hlp[i]);
  256.       fatal((char *)0);
  257.     case 's':
  258.       shell_path = optarg;
  259.       break;
  260.     case 'c':
  261.       cat_path = optarg;
  262.       break;
  263.     case 'm':
  264.       menu_fname = optarg;
  265.       break;
  266.     case 'v':
  267.       verbose++;
  268.       break;
  269.     case 'D':
  270.       debug_mode++;
  271.       break;
  272.     case '?':
  273.       fatal((char *)0);
  274.     }
  275.   }
  276.  
  277.   argcc = argc;
  278.   argvv = argv;
  279.   progname = argv[0];
  280.   if (strcmp(menu_fname, "-")) {
  281.     close(0);
  282.  
  283.     if (open(menu_fname, O_RDONLY) < 0) {
  284.       char buf[80];
  285.  
  286.       sprintf(buf, "cannot open menu definition: %s", menu_fname);
  287.       fatal(buf);
  288.     }
  289.   }
  290.  
  291.   if ((tty_in = open("/dev/tty", O_RDONLY)) < 0)
  292.     fatal("cannot open tty - must be run interactively");
  293.   tty_file = fdopen(tty_in, "r");
  294.  
  295.   cmd_path = debug_mode ? cat_path : shell_path;
  296.   if (cmd_name = strrchr(cmd_path, '/'))
  297.     cmd_name++;
  298.   else
  299.     cmd_name = cmd_path;
  300. }
  301.  
  302. struct parm *make_new_parm(identifier, prompt)
  303. char *identifier;
  304. char *prompt;
  305. {
  306.   struct parm *parm_ptr = (struct parm *)malloc(sizeof(struct parm));
  307.  
  308.   if (!parm_ptr)
  309.     fatal("malloc() error");
  310.  
  311.   parm_ptr->next = (struct parm *)0;
  312.   parm_ptr->prompt = prompt;
  313.   parm_ptr->identifier = identifier;
  314.   parm_ptr->value = "";
  315.  
  316.   return parm_ptr;
  317. }
  318.  
  319. struct item *make_new_item(prompt, command, parms)
  320. char *prompt;
  321. char *command;
  322. struct parm *parms;
  323. {
  324.   struct item *item_ptr = (struct item *)malloc(sizeof(struct item));
  325.  
  326.   if (!item_ptr)
  327.     fatal("malloc() error");
  328.  
  329.   item_ptr->next = (struct item *)0;
  330.   item_ptr->prompt = prompt;
  331.   item_ptr->command = command;
  332.   item_ptr->parms = parms;
  333.  
  334.   return item_ptr;
  335. }
  336.  
  337. char tty_bp[1024];
  338. char tty_caps[1024];
  339. char *term_cm;
  340. char *term_so;
  341. char *term_se;
  342. int term_sg;
  343. char *term_cl;
  344. int term_lines;
  345. char PC;
  346. char *BC;
  347. char *UP;
  348. short ospeed;
  349.  
  350. int outc(c)
  351. int c;
  352. {
  353.   putc(c, stdout);
  354. }
  355.  
  356. init_terminal()
  357. {
  358.   char *getenv();
  359.   char *tty_type = getenv("TERM");
  360.   char *cp = tty_caps;
  361.   char *tgetstr();
  362.  
  363.   if (!tty_type || tgetent(tty_bp, tty_type) <= 0) {
  364.     clear_flag =
  365.       bold_flag = 0;
  366.     return;
  367.   }
  368.  
  369.   PC = *tgetstr("pc", &cp);
  370.   BC = tgetstr("bc", &cp);
  371.   UP = tgetstr("up", &cp);
  372. #ifdef TERMIO
  373.   {
  374. #include <sys/termio.h>
  375.  
  376.     struct termio termio;
  377.  
  378.     ioctl(0, TCGETA, &termio);
  379.     ospeed = termio.c_cflag & CBAUD;
  380.   }
  381. #undef ECHO /* conflicts with lex code */
  382. #endif /* TERMIO */
  383.   term_cm = tgetstr("cm", &cp);
  384.   if (bold_flag) {
  385.     term_so = tgetstr("so", &cp);
  386.     term_se = tgetstr("se", &cp);
  387.     term_sg = tgetnum("sg");
  388.     if (!term_so)
  389.       bold_flag = 0;
  390.   }
  391.   if (clear_flag) {
  392.     term_cl = tgetstr("cl", &cp);
  393.     term_lines = tgetnum("li");
  394.     if (!term_cl)
  395.       clear_flag = 0;
  396.   }
  397. }
  398.  
  399. do_menu()
  400. {
  401.   int item_idx;
  402.   int pid;
  403.  
  404.   while (1) {
  405.   again:
  406.     setjmp(env);
  407.     set_signals(SIGS_FOR_JMP);
  408.  
  409.     while (1) {
  410.       char buf[80];
  411.       char *cp;
  412.       int rsp;
  413.  
  414.       display_menu();
  415.       fgets(buf, 80, tty_file);
  416.       if (cp = strchr(buf, '\n'))
  417.     *cp = '\0';
  418.  
  419.       if (strchr(buf, 'Q') || strchr(buf, 'q'))
  420.     exit(0);
  421.  
  422.       if (strchr(buf, '?')) {
  423.     display_menu_flag = 1;
  424.     goto again;
  425.       }
  426.  
  427.       if (sscanf(buf, "%d", &item_idx) != 1) {
  428.     printf("'%s' is not a legal response\n", buf);
  429.     goto again;
  430.       }
  431.  
  432.       if (--item_idx < 0 || item_idx >= max_item) {
  433.     printf("'%s' is not a legal response\n", buf);
  434.     goto again;
  435.       }
  436.       else
  437.     break;
  438.     }
  439.  
  440.     selected_item = menu_head;
  441.     while (item_idx-- > 0)
  442.       selected_item = selected_item->next;
  443.  
  444.     selected_parms = selected_item->parms;
  445.  
  446.     while (selected_parms) {
  447.       char buf[256];
  448.       char *cp;
  449.  
  450.       printf("%s: ", selected_parms->prompt);
  451.       fflush(stdout);
  452.       fgets(buf, 255, tty_file);
  453.       if (cp = strchr(buf, '\n'))
  454.     *cp = '\0';
  455.  
  456.       strcpy(selected_parms->value = malloc(strlen(buf) + 1), buf);
  457.       selected_parms = selected_parms->next;
  458.     }
  459.  
  460.     tmp_fname = tmpnam((char *)0);
  461.     set_signals(SIGS_FOR_CHILD);
  462.     if ((tmp_file = fopen(tmp_fname, "w")) == NULL)
  463.       fatal("cannot create temp file for shell");
  464.     if (verbose)
  465.       fprintf(tmp_file, "set -xv\n");
  466.     for (selected_parms=selected_item->parms;selected_parms;
  467.      selected_parms=selected_parms->next) {
  468.       fprintf(tmp_file, "%s=\"%s\"\n", selected_parms->identifier,
  469.           selected_parms->value);
  470.       free(selected_parms->value);
  471.       selected_parms->value = "";
  472.     }
  473.     fprintf(tmp_file, "%s\n", selected_item->command);
  474.     fclose(tmp_file);
  475.  
  476.     if ( !(pid = fork()) ) {
  477.       /* reset signals so that DEL,... work correctly */
  478.       reset_signals();
  479.       close(0);
  480.       dup(tty_in);
  481.       close(tty_in);
  482.       fclose(tty_file);
  483.       execl(cmd_path, cmd_name, tmp_fname, (char *)0);
  484.       fatal("exec of command failed");
  485.     }
  486.  
  487.     wait_for_child(pid);
  488.     unlink(tmp_fname);
  489.     tmp_fname = (char *)0;
  490.     if (clear_flag) {
  491.       char buf[80];
  492.  
  493.       printf("[Press Return to Continue]");
  494.       fflush(stdout);
  495.       fgets(buf, 80, tty_file);
  496.     }
  497.   }
  498.   reset_signals();
  499. }
  500.  
  501. display_menu()
  502. {
  503.   struct item *ptr = menu_head;
  504.   int i;
  505.  
  506.   /* if we clear the screen, then do it, otherwise skip a line */
  507.   if (clear_flag)
  508.     tputs(term_cl, term_lines, outc);
  509.   else
  510.     putc('\n', stdout);
  511.  
  512.   /* this is not correct for magic cookie tubes - but I don't feel
  513.      like counting lines in menu_title, maintaining line counts in the
  514.      case we don't clear-screen-before-displaying, ...
  515.      So if you have a stupid tube - it is going to flash */
  516.   if (bold_flag) {
  517.     tputs(term_so, 1, outc);
  518.     printf("%s", menu_title);
  519.     tputs(term_se, 1, outc);
  520.     putc('\n', stdout);
  521.   }
  522.   else
  523.     printf("%s\n", menu_title);
  524.  
  525.   if (display_menu_flag) {
  526.     for (i=0;ptr;i++,ptr = ptr->next)
  527.       printf("%2d. %s\n", i + 1, ptr->prompt);
  528.     max_item = i;
  529.   }
  530.  
  531.   printf( always_display_menu_flag ? "Q) to End - choice? " :
  532.      "Q) to End, ?) for Menu - choice? ");
  533.   fflush(stdout);
  534.  
  535.   display_menu_flag = always_display_menu_flag;
  536. }
  537.  
  538. #include "lex.yy.c"
  539.  
  540.  
  541. fatal(s)
  542. char *s;
  543. {
  544.   extern int errno;
  545.   char msg_buf[80];
  546.  
  547.   fprintf(stderr, use_msg, progname);
  548.   if (s)
  549.     fprintf(stderr, "%s\n", s);
  550.  
  551.   if (errno) {
  552.     sprintf(msg_buf, "fatal error '%s': line %d", menu_fname, line_number);
  553.     perror(msg_buf);
  554.   }
  555.   exit(1);
  556. }
  557.  
  558. void trapoid(sig)
  559. int sig;
  560. {
  561.   if (tmp_fname)
  562.     unlink(tmp_fname);
  563.  
  564.   exit(sig);
  565. }
  566.  
  567. do_longjmp(sig)
  568. int sig;
  569. {
  570.   longjmp(env, 0);
  571. }
  572.  
  573. wait_for_child(pid)
  574. int pid;
  575. {
  576.   int wait_ret;
  577.   int status;
  578.   extern int errno;
  579.  
  580.   while ((wait_ret = wait(&status)) != pid) {
  581.     /* test to see if child is still there - if not, then return */
  582.     if (kill(pid, 0) < 0)
  583.       return;
  584.   }
  585. }
  586.  
  587. set_signals(flag)
  588. int flag;
  589. {
  590.   switch (flag) {
  591.   case SIGS_FOR_JMP:
  592.     signal(SIGHUP, trapoid);
  593.     signal(SIGINT, do_longjmp);
  594.     signal(SIGQUIT, do_longjmp);
  595.     signal(SIGTERM, trapoid);
  596.     break;
  597.   case SIGS_FOR_CHILD:
  598.     signal(SIGHUP, trapoid);
  599.     signal(SIGINT, SIG_IGN);
  600.     signal(SIGQUIT, SIG_IGN);
  601.     signal(SIGTERM, trapoid);
  602.     break;
  603.   }
  604. }
  605.  
  606. reset_signals()
  607. {
  608.   signal(SIGHUP, SIG_DFL);
  609.   signal(SIGINT, SIG_DFL);
  610.   signal(SIGQUIT, SIG_DFL);
  611.   signal(SIGTERM, SIG_DFL);
  612.   signal(SIGCLD, SIG_DFL);
  613. }
  614.