home *** CD-ROM | disk | FTP | other *** search
Lex Description | 1990-03-10 | 11.6 KB | 614 lines |
- %{
- /* @(#)dumb_menu.y 1.3 90/03/08 */
-
- static char *cpy_str =
- "Copyright (c), Mike Howard, 1990, all rights reserved";
-
- /* Conditions of use:
-
- This software is not for sale and is not to be sold by or
- to anyone.
-
- You may use this software and may distribute it to anyone
- you wish to provided you distribute the entire distribution
- package w/o any deletions (i.e. include all the source code).
-
- I do not warrent this software to do anything at all and
- am not responsible for anything which happens as a result of
- its use.
- */
-
- #include <stdio.h>
- #include <fcntl.h>
- #include <string.h>
- #include <signal.h>
- #include <setjmp.h>
-
- struct parm {
- struct parm *next;
- char *prompt;
- char *identifier;
- char *value;
- };
-
- struct item {
- struct item *next;
- char *prompt;
- char *command;
- struct parm *parms;
- };
-
- struct item *menu_head;
- struct item *menu_tail;
-
- int max_item;
-
- struct parm *parm_list;
-
- char *menu_title;
-
- char *malloc();
- char *realloc();
-
- int lex_errors;
- int yacc_errors;
- int line_number;
-
- /* flags */
- int clear_flag;
- int bold_flag;
- int always_display_menu_flag;
-
- /* Menus begin with a title definition
- title { text for the title }
-
- This is followed by one or more menu-item definitions of the form:
-
- item { prompt } { shell command }
- parm "name" { prompt }
- parm "name" { prompt }
- ;
-
- the crud in between braces may contain any character, including
- escapped braces and back-slash (\).
- The crud in between the double quotes may ONLY contain letters, digits,
- and underscores;
-
- Sub-menus are formed by running dumb_menu as the shell process, pointed
- to an appropriate sub-menu definition file.
-
- There is no provision for menus which require more than one screen
- to display.
- */
-
- #define DEBUG0(fmt) if(debug_mode>1)printf(fmt);
- #define DEBUG1(fmt,aa) if(debug_mode>1)printf(fmt,aa);
- #define DEBUG2(fmt,aa,bb) if(debug_mode>1)printf(fmt,aa,bb);
- #define DEBUG3(fmt,aa,bb,cc) if(debug_mode>1)printf(fmt,aa,bb,cc);
-
- %}
-
- %union {
- int ival;
- char *txt;
- char chr;
- double dbl;
- struct item *itm;
- struct parm *prm;
- }
-
- %token <ival> NUMBER
- %token <dbl> FLOAT
- %token <txt> TEXT PARM_NAME
- %token PARM ITEM TITLE ERROR
- %token CLEAR BOLD ALWAYS_SHOW
-
- %type <itm> menu item
- %type <prm> parm
-
- %%
-
- menu : title menu_flags item
- {
- menu_head =
- menu_tail = $3;
- DEBUG1("Initial Menu Item:\n %s\n", $3->prompt);
- }
- | menu item
- {
- menu_tail->next = $2;
- menu_tail = $2;
- DEBUG1("Additional Menu Item:\n %s\n", $2->prompt);
- }
- ;
-
- title : TITLE TEXT
- {
- menu_title = $2;
- DEBUG1("menu title '%s'\n", $2);
- }
- ;
-
- menu_flags :
- | menu_flags menu_flag
- ;
-
- menu_flag : CLEAR
- {
- clear_flag++;
- }
- | BOLD
- {
- bold_flag++;
- }
- | ALWAYS_SHOW
- {
- always_display_menu_flag++;
- }
- ;
-
- item : ITEM TEXT TEXT parms ';'
- {
- $$ = make_new_item($2, $3, parm_list);
- parm_list = (struct parm *)0;
- }
- ;
-
- parms : /* empty */
- | parms parm
- ;
-
- parm : PARM PARM_NAME TEXT
- {
- $$ = make_new_parm($2, $3);
- $$->next = parm_list;
- parm_list = $$;
- DEBUG2("parm: %s\n'%s'\n", $2, $3);
- }
- ;
-
- %%
-
- char *use_msg = "usage: %s [-h | option(s) ]\n";
-
- extern char *optarg;
- extern int optind, opterr;
- int tty_in;
- FILE *tty_file;
- int argcc;
- char **argvv;
- char *progname;
- char *in_fname = "stdin";
- char *menu_fname = "./menu.def";
- char *shell_path = "/bin/sh";
- char *cat_path = "/bin/cat";
- char *cmd_path;
- char *cmd_name;
-
- struct item *selected_item;
- struct parm *selected_parms;
- FILE *tmp_file;
- char *tmp_fname;
-
- int verbose;
- int debug_mode;
-
- char *hlp[] = {
- "Option Function",
- "-m file set menu-definition file name to 'file' (menu.def)",
- "-s path path to shell to execute scripts",
- "-c path path to 'cat' for simple debug mode",
- "-v make command execution verbose (via set -xv)",
- "-D increment debug mode",
- (char *)0};
-
- int display_menu_flag = 1;
- jmp_buf env;
- #define SIGS_FOR_JMP 1
- #define SIGS_FOR_CHILD 2
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- int item_idx;
-
- init(argc, argv);
-
- if (yyparse())
- fatal("Parse Error");
-
- if (lex_errors || yacc_errors)
- fatal("corrupt menu definition");
-
- if (debug_mode) {
- item_idx = 1;
- for (selected_item=menu_head;selected_item;
- selected_item = selected_item->next) {
- printf("%2d. %s\n", item_idx++, selected_item->prompt);
- printf("%s\n", selected_item->command);
- for (selected_parms=selected_item->parms;selected_parms;
- selected_parms = selected_parms->next)
- printf("%s: '%s'\n", selected_parms->prompt,
- selected_parms->identifier);
- }
- }
-
- init_terminal();
-
- do_menu();
- }
-
- init(argc, argv)
- int argc;
- char **argv;
- {
- int i;
- int c;
- extern char *optarg;
- extern int optind, opterr;
-
- while ((c = getopt(argc, argv, "hcsm:vD")) != EOF) {
- switch (c) {
- case 'h':
- for (i=0;hlp[i];i++)
- printf("%s\n", hlp[i]);
- fatal((char *)0);
- case 's':
- shell_path = optarg;
- break;
- case 'c':
- cat_path = optarg;
- break;
- case 'm':
- menu_fname = optarg;
- break;
- case 'v':
- verbose++;
- break;
- case 'D':
- debug_mode++;
- break;
- case '?':
- fatal((char *)0);
- }
- }
-
- argcc = argc;
- argvv = argv;
- progname = argv[0];
- if (strcmp(menu_fname, "-")) {
- close(0);
-
- if (open(menu_fname, O_RDONLY) < 0) {
- char buf[80];
-
- sprintf(buf, "cannot open menu definition: %s", menu_fname);
- fatal(buf);
- }
- }
-
- if ((tty_in = open("/dev/tty", O_RDONLY)) < 0)
- fatal("cannot open tty - must be run interactively");
- tty_file = fdopen(tty_in, "r");
-
- cmd_path = debug_mode ? cat_path : shell_path;
- if (cmd_name = strrchr(cmd_path, '/'))
- cmd_name++;
- else
- cmd_name = cmd_path;
- }
-
- struct parm *make_new_parm(identifier, prompt)
- char *identifier;
- char *prompt;
- {
- struct parm *parm_ptr = (struct parm *)malloc(sizeof(struct parm));
-
- if (!parm_ptr)
- fatal("malloc() error");
-
- parm_ptr->next = (struct parm *)0;
- parm_ptr->prompt = prompt;
- parm_ptr->identifier = identifier;
- parm_ptr->value = "";
-
- return parm_ptr;
- }
-
- struct item *make_new_item(prompt, command, parms)
- char *prompt;
- char *command;
- struct parm *parms;
- {
- struct item *item_ptr = (struct item *)malloc(sizeof(struct item));
-
- if (!item_ptr)
- fatal("malloc() error");
-
- item_ptr->next = (struct item *)0;
- item_ptr->prompt = prompt;
- item_ptr->command = command;
- item_ptr->parms = parms;
-
- return item_ptr;
- }
-
- char tty_bp[1024];
- char tty_caps[1024];
- char *term_cm;
- char *term_so;
- char *term_se;
- int term_sg;
- char *term_cl;
- int term_lines;
- char PC;
- char *BC;
- char *UP;
- short ospeed;
-
- int outc(c)
- int c;
- {
- putc(c, stdout);
- }
-
- init_terminal()
- {
- char *getenv();
- char *tty_type = getenv("TERM");
- char *cp = tty_caps;
- char *tgetstr();
-
- if (!tty_type || tgetent(tty_bp, tty_type) <= 0) {
- clear_flag =
- bold_flag = 0;
- return;
- }
-
- PC = *tgetstr("pc", &cp);
- BC = tgetstr("bc", &cp);
- UP = tgetstr("up", &cp);
- #ifdef TERMIO
- {
- #include <sys/termio.h>
-
- struct termio termio;
-
- ioctl(0, TCGETA, &termio);
- ospeed = termio.c_cflag & CBAUD;
- }
- #undef ECHO /* conflicts with lex code */
- #endif /* TERMIO */
- term_cm = tgetstr("cm", &cp);
- if (bold_flag) {
- term_so = tgetstr("so", &cp);
- term_se = tgetstr("se", &cp);
- term_sg = tgetnum("sg");
- if (!term_so)
- bold_flag = 0;
- }
- if (clear_flag) {
- term_cl = tgetstr("cl", &cp);
- term_lines = tgetnum("li");
- if (!term_cl)
- clear_flag = 0;
- }
- }
-
- do_menu()
- {
- int item_idx;
- int pid;
-
- while (1) {
- again:
- setjmp(env);
- set_signals(SIGS_FOR_JMP);
-
- while (1) {
- char buf[80];
- char *cp;
- int rsp;
-
- display_menu();
- fgets(buf, 80, tty_file);
- if (cp = strchr(buf, '\n'))
- *cp = '\0';
-
- if (strchr(buf, 'Q') || strchr(buf, 'q'))
- exit(0);
-
- if (strchr(buf, '?')) {
- display_menu_flag = 1;
- goto again;
- }
-
- if (sscanf(buf, "%d", &item_idx) != 1) {
- printf("'%s' is not a legal response\n", buf);
- goto again;
- }
-
- if (--item_idx < 0 || item_idx >= max_item) {
- printf("'%s' is not a legal response\n", buf);
- goto again;
- }
- else
- break;
- }
-
- selected_item = menu_head;
- while (item_idx-- > 0)
- selected_item = selected_item->next;
-
- selected_parms = selected_item->parms;
-
- while (selected_parms) {
- char buf[256];
- char *cp;
-
- printf("%s: ", selected_parms->prompt);
- fflush(stdout);
- fgets(buf, 255, tty_file);
- if (cp = strchr(buf, '\n'))
- *cp = '\0';
-
- strcpy(selected_parms->value = malloc(strlen(buf) + 1), buf);
- selected_parms = selected_parms->next;
- }
-
- tmp_fname = tmpnam((char *)0);
- set_signals(SIGS_FOR_CHILD);
- if ((tmp_file = fopen(tmp_fname, "w")) == NULL)
- fatal("cannot create temp file for shell");
- if (verbose)
- fprintf(tmp_file, "set -xv\n");
- for (selected_parms=selected_item->parms;selected_parms;
- selected_parms=selected_parms->next) {
- fprintf(tmp_file, "%s=\"%s\"\n", selected_parms->identifier,
- selected_parms->value);
- free(selected_parms->value);
- selected_parms->value = "";
- }
- fprintf(tmp_file, "%s\n", selected_item->command);
- fclose(tmp_file);
-
- if ( !(pid = fork()) ) {
- /* reset signals so that DEL,... work correctly */
- reset_signals();
- close(0);
- dup(tty_in);
- close(tty_in);
- fclose(tty_file);
- execl(cmd_path, cmd_name, tmp_fname, (char *)0);
- fatal("exec of command failed");
- }
-
- wait_for_child(pid);
- unlink(tmp_fname);
- tmp_fname = (char *)0;
- if (clear_flag) {
- char buf[80];
-
- printf("[Press Return to Continue]");
- fflush(stdout);
- fgets(buf, 80, tty_file);
- }
- }
- reset_signals();
- }
-
- display_menu()
- {
- struct item *ptr = menu_head;
- int i;
-
- /* if we clear the screen, then do it, otherwise skip a line */
- if (clear_flag)
- tputs(term_cl, term_lines, outc);
- else
- putc('\n', stdout);
-
- /* this is not correct for magic cookie tubes - but I don't feel
- like counting lines in menu_title, maintaining line counts in the
- case we don't clear-screen-before-displaying, ...
- So if you have a stupid tube - it is going to flash */
- if (bold_flag) {
- tputs(term_so, 1, outc);
- printf("%s", menu_title);
- tputs(term_se, 1, outc);
- putc('\n', stdout);
- }
- else
- printf("%s\n", menu_title);
-
- if (display_menu_flag) {
- for (i=0;ptr;i++,ptr = ptr->next)
- printf("%2d. %s\n", i + 1, ptr->prompt);
- max_item = i;
- }
-
- printf( always_display_menu_flag ? "Q) to End - choice? " :
- "Q) to End, ?) for Menu - choice? ");
- fflush(stdout);
-
- display_menu_flag = always_display_menu_flag;
- }
-
- #include "lex.yy.c"
-
-
- fatal(s)
- char *s;
- {
- extern int errno;
- char msg_buf[80];
-
- fprintf(stderr, use_msg, progname);
- if (s)
- fprintf(stderr, "%s\n", s);
-
- if (errno) {
- sprintf(msg_buf, "fatal error '%s': line %d", menu_fname, line_number);
- perror(msg_buf);
- }
- exit(1);
- }
-
- void trapoid(sig)
- int sig;
- {
- if (tmp_fname)
- unlink(tmp_fname);
-
- exit(sig);
- }
-
- do_longjmp(sig)
- int sig;
- {
- longjmp(env, 0);
- }
-
- wait_for_child(pid)
- int pid;
- {
- int wait_ret;
- int status;
- extern int errno;
-
- while ((wait_ret = wait(&status)) != pid) {
- /* test to see if child is still there - if not, then return */
- if (kill(pid, 0) < 0)
- return;
- }
- }
-
- set_signals(flag)
- int flag;
- {
- switch (flag) {
- case SIGS_FOR_JMP:
- signal(SIGHUP, trapoid);
- signal(SIGINT, do_longjmp);
- signal(SIGQUIT, do_longjmp);
- signal(SIGTERM, trapoid);
- break;
- case SIGS_FOR_CHILD:
- signal(SIGHUP, trapoid);
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- signal(SIGTERM, trapoid);
- break;
- }
- }
-
- reset_signals()
- {
- signal(SIGHUP, SIG_DFL);
- signal(SIGINT, SIG_DFL);
- signal(SIGQUIT, SIG_DFL);
- signal(SIGTERM, SIG_DFL);
- signal(SIGCLD, SIG_DFL);
- }
-