From 2aaf83c29b91157ee52a69e576f6bcdfb7820c16 Mon Sep 17 00:00:00 2001 From: wesommer Date: Mon, 3 Aug 1987 04:16:51 +0000 Subject: [PATCH] Here's another, which is probably better. --- clients/moira/menu.c | 377 ++++++++++++++++++++++++++++++++----------- 1 file changed, 285 insertions(+), 92 deletions(-) diff --git a/clients/moira/menu.c b/clients/moira/menu.c index ee75bded..513074b3 100644 --- a/clients/moira/menu.c +++ b/clients/moira/menu.c @@ -1,4 +1,19 @@ /* + * Copyright 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + * + * $Source$ + * $Author$ + * $Header$ + * $Log$ + * Revision 1.2 1987-08-03 04:16:51 wesommer + * Here's another, which is probably better. + * + * Revision 1.1 87/07/31 18:02:23 ambar + * Initial revision + * + * * Generic menu system module. * * Basically, we define an enormous tree structure which represents the @@ -9,8 +24,13 @@ * about anything. */ +#ifndef lint +static char rcsid_menu_c[] = "$Header$"; +#endif lint + #include #include +#include #include "menu.h" #define MAX(A,B) ((A) > (B) ? (A) : (B)) @@ -18,6 +38,9 @@ #define MIN_INPUT 2 /* Minimum number of lines for input window */ +char *strcpy(); +char *strncpy(); + /* Structure for holding current displayed menu */ struct menu_screen { WINDOW *ms_screen; /* Window for this menu */ @@ -27,6 +50,10 @@ struct menu_screen { int ms_input_y; /* Input subwindow reference coordinate */ } *cur_ms; +#define NULLMS ((struct menu_screen *) 0) + +Menu *top_menu; /* Root for command search */ + /* * Start_menu takes a menu as an argument. It initializes curses u.s.w., * and a quit in any submenu should unwind back to here. (it might not, @@ -36,16 +63,29 @@ struct menu_screen { Start_menu(m) Menu *m; { + struct menu_screen *make_ms(); + if(initscr() == ERR) { fputs("Can't initialize curses!\n", stderr); - exit(1); + Start_no_menu(m); } raw(); /* We parse & print everything ourselves */ noecho(); - Do_menu(m); /* Run the menu */ + cur_ms = make_ms(0); /* So we always have some current menu_screen */ + top_menu = m; + (void) Do_menu(m); /* Run the menu */ endwin(); } +/* Like Start_menu, except it doesn't print menus and doesn't use curses */ +Start_no_menu(m) +Menu *m; +{ + cur_ms = NULLMS; + top_menu = m; + (void) Do_menu(m); +} + /* * Create a new menu screen template with the specified menu length * and return it. @@ -72,8 +112,8 @@ int length; 0); scrollok(ms->ms_input, TRUE); - wmove(ms->ms_input, 0, 0); - wclear(ms->ms_screen); + (void) wmove(ms->ms_input, 0, 0); + (void) wclear(ms->ms_screen); return(ms); } @@ -88,7 +128,7 @@ struct menu_screen *ms; delwin(ms->ms_menu); delwin(ms->ms_input); delwin(ms->ms_screen); - free(ms); + free((char *)ms); } /* @@ -99,80 +139,106 @@ Menu *m; { struct menu_screen *my_ms, *old_cur_ms; char argvals[MAX_ARGC][MAX_ARGLEN]; /* This is where args are stored */ + char buf[MAX_ARGC * MAX_ARGLEN]; char *argv[MAX_ARGC]; int line; + int i; + struct menu_line *command, *Find_command(); int argc; int quitflag; - /* Initialize argv */ - for(argc = 0; argc < MAX_ARGC; argc++) argv[argc] = argvals[argc]; - /* Entry function gets called with old menu_screen still current */ if(m->m_entry != NULLFUNC) m->m_entry(m); - /* Get a menu_screen */ - old_cur_ms = cur_ms; - cur_ms = my_ms = make_ms(m->m_length + 2); + /* The following get run only in curses mode */ + if(cur_ms != NULLMS) { + /* Get a menu_screen */ + old_cur_ms = cur_ms; + cur_ms = my_ms = make_ms(m->m_length + 2); - /* Now print the title and the menu */ - wmove(my_ms->ms_title, 0, MAX(0, (COLS - strlen(m->m_title))>>1)); - wstandout(my_ms->ms_title); - waddstr(my_ms->ms_title, m->m_title); - wstandend(my_ms->ms_title); + /* Now print the title and the menu */ + (void) wmove(my_ms->ms_title, 0, MAX(0, (COLS - strlen(m->m_title))>>1)); + (void) wstandout(my_ms->ms_title); + (void) waddstr(my_ms->ms_title, m->m_title); + (void) wstandend(my_ms->ms_title); + + for(line = 0; line < m->m_length; line++) { + (void) wmove(my_ms->ms_menu, line, 0); + (void) wprintw(my_ms->ms_menu, "%2d. (%-12s) %s.", line+1, + m->m_lines[line].ml_command, + m->m_lines[line].ml_doc); + } + (void) wmove(my_ms->ms_menu, line++, 0); + (void) waddstr(my_ms->ms_menu, " r. (return ) Return to previous menu."); + (void) wmove(my_ms->ms_menu, line, 0); + (void) waddstr(my_ms->ms_menu, " q. (quit ) Quit."); - for(line = 0; line < m->m_length; line++) { - wmove(my_ms->ms_menu, line, 0); - wprintw(my_ms->ms_menu, "%2d. (%-8s) %s.", line+1, - m->m_lines[line].ml_command, - m->m_lines[line].ml_doc); } - wmove(my_ms->ms_menu, line++, 0); - waddstr(my_ms->ms_menu, " r. (return ) Return to previous menu."); - wmove(my_ms->ms_menu, line, 0); - waddstr(my_ms->ms_menu, " q. (quit ) Quit."); - refresh_ms(my_ms); for(;;) { /* This will be set by a return val from func or submenu */ quitflag = DM_NORMAL; + /* This is here because we may be coming from another menu */ + if(cur_ms != NULL) touchwin(my_ms->ms_screen); /* Get a command */ - Prompt_input("Command: ", argvals[0], sizeof(argvals[0])); - /* See if it matches anything (this is kind of dumb, for now) */ - if((line = atoi(argvals[0])) > 0 && line <= m->m_length) { - line--; - /* Send the command into the argv */ - strcpy(argvals[0], m->m_lines[line].ml_command); - /* Show that we're working on it */ - Put_message(m->m_lines[line].ml_doc); - /* Get arguments, if any */ - for(argc = 1; argc < m->m_lines[line].ml_argc; argc++) { - Prompt_input(m->m_lines[line].ml_args[argc].ma_prompt, - argvals[argc], sizeof(argvals[argc])); - } - if(m->m_lines[line].ml_function != NULLFUNC) { - /* If it's got a function, call it */ - quitflag = m->m_lines[line].ml_function(argv, argc); - } else if(m->m_lines[line].ml_submenu != NULLMENU) { - /* Else see if it is a submenu */ - quitflag = Do_menu(m->m_lines[line].ml_submenu); - } else { - /* If it's got neither, something is wrong */ - Put_message("*INTERNAL ERROR: NO FUNCTION OR MENU FOR LINE*"); - } - } else if(!strcmp(argv[0], "r") || !strcmp(argv[0], "q")) { + Prompt_input("Command: ", buf, sizeof(buf)); + /* Parse it into the argument list */ + /* If there's nothing there, try again */ + /* Initialize argv */ + for(argc = 0; argc < MAX_ARGC; argc++) argv[argc] = argvals[argc]; + + if((argc = Parse_words(buf, argv, MAX_ARGLEN)) == 0) continue; + if((line = atoi(argv[0])) > 0 && line <= m->m_length) { + command = &m->m_lines[line-1]; + } else if(!strcmp(argv[0], "r") + || !strcmp(argv[0], "q") + || !strcmp(argv[0], "return") + || !strcmp(argv[0], "quit")) { /* here if it's either return or quit */ - cur_ms = old_cur_ms; - destroy_ms(my_ms); + if(cur_ms != NULLMS) { + cur_ms = old_cur_ms; + destroy_ms(my_ms); + } if(m->m_exit != NULLFUNC) m->m_exit(m); return(*argv[0] == 'r' ? DM_NORMAL : DM_QUIT); + /* finally, try to find it using Find_command */ + } else if ((command = Find_command (argvals[0])) == + (struct menu_line *) 0) { + Put_message("Command not recognized"); + continue; + } + /* If we got to here, command is a valid menu_line */ + /* Send the offical command name into the argv */ + (void) strcpy(argvals[0], command->ml_command); + /* Show that we're working on it */ + Put_message(command->ml_doc); + /* Print args that we've already got */ + for(i = 1; i < argc; i++) { + if(command->ml_args[i].ma_prompt == NULL) break; + (void) sprintf(buf, "%s%s", command->ml_args[i].ma_prompt, + argv[i]); + Put_message(buf); + } + /* Get remaining arguments, if any */ + for(; argc < command->ml_argc; argc++) { + Prompt_input(command->ml_args[argc].ma_prompt, + argvals[argc], sizeof(argvals[argc])); + } + if(command->ml_function != NULLFUNC) { + /* If it's got a function, call it */ + quitflag = command->ml_function(argc, argv); + } else if(command->ml_submenu != NULLMENU) { + /* Else see if it is a submenu */ + quitflag = Do_menu(command->ml_submenu); } else { - /* Couldn't find it, give up */ - Put_message("Command not recognized"); - continue; /* No good */ + /* If it's got neither, something is wrong */ + Put_message("*INTERNAL ERROR: NO FUNCTION OR MENU FOR LINE*"); } if(quitflag == DM_QUIT) { - cur_ms = old_cur_ms; - destroy_ms(my_ms); + if(cur_ms != NULLMS) { + cur_ms = old_cur_ms; + destroy_ms(my_ms); + } if(m->m_exit != NULLFUNC) m->m_exit(m); return(DM_QUIT); } @@ -189,47 +255,101 @@ int buflen; char *p; int y, x, oldx; - waddstr(cur_ms->ms_input, prompt); - getyx(cur_ms->ms_input, y, x); - oldx = x; - for (p = buf; p - buf < buflen; ) { - wmove(cur_ms->ms_input, y, x); - wclrtoeol(cur_ms->ms_input); - refresh_ms(cur_ms); - c = getchar(); - switch (c) { - case 'L' & 037: - touchwin(cur_ms->ms_screen); - break; - case '\n': case '\r': - waddch(cur_ms->ms_input, '\n'); - *p = '\0'; - return; - case '\b': - case '\177': - if (p > buf) { - p--; - x--; + if(cur_ms != NULLMS) { + (void) waddstr(cur_ms->ms_input, prompt); + getyx(cur_ms->ms_input, y, x); + oldx = x; + for (p = buf; p - buf < buflen; ) { + (void) wmove(cur_ms->ms_input, y, x); + (void) wclrtoeol(cur_ms->ms_input); + refresh_ms(cur_ms); + c = getchar(); + switch (c) { + case 'L' & 037: + touchwin(cur_ms->ms_screen); + break; + case '\n': case '\r': + (void) waddch(cur_ms->ms_input, '\n'); + *p = '\0'; + Start_paging(); + return; + case '\b': + case '\177': + if (p > buf) { + p--; + x--; + } + break; + case 'U' & 037: case '\007': case '\033': + x = oldx; + break; + default: + (void) waddch(cur_ms->ms_input, c); + *p++ = c; + x++; + break; } - break; - case 'U' & 037: case '\007': case '\033': - x = oldx; - break; - default: - waddch(cur_ms->ms_input, c); - *p++ = c; - x++; - break; } + } else { + printf("%s", prompt); + (void) gets(buf); + Start_paging(); + return; } } +int lines_left; + +/* Start paging */ +/* This routine will cause the most recently put message to be the + one at the top of the screen when a ---More--- prompt is displayed */ +Start_paging() +{ + if(cur_ms != NULLMS) { + lines_left = LINES - cur_ms->ms_input_y - 1; + } else { + lines_left = 23; + } +} + +/* Turn off paging */ +Stop_paging() +{ + lines_left = -1; +} + /* Print a message in the input window of cur_ms */ Put_message(msg) char *msg; { - wprintw(cur_ms->ms_input, "%s\n", msg); - refresh_ms(cur_ms); + int y, x; + + if(lines_left >= 0) { + if(--lines_left == 0) { + /* Give the user a more prompt */ + if(cur_ms != NULLMS) { + (void) wstandout(cur_ms->ms_input); + (void) wprintw(cur_ms->ms_input, "---More---"); + (void) wstandend(cur_ms->ms_input); + refresh_ms(cur_ms); + (void) getchar(); /* We don't care what it is */ + getyx(cur_ms->ms_input, y, x); + (void) wmove(cur_ms->ms_input, y, 0); + (void) wclrtoeol(cur_ms->ms_input); + } else { + printf("---More (hit return)---"); + (void) getchar(); + } + Start_paging(); /* Reset lines_left */ + } + } + + if(cur_ms != NULLMS) { + (void) wprintw(cur_ms->ms_input, "%s\n", msg); +/* refresh_ms(cur_ms); */ + } else { + puts(msg); + } } /* Refresh a menu_screen onto the real screen */ @@ -239,7 +359,80 @@ struct menu_screen *ms; int y, x; getyx(ms->ms_input, y, x); - wmove(ms->ms_screen, y + ms->ms_input_y, x); - touchwin(ms->ms_screen); - wrefresh(ms->ms_screen); + (void) wmove(ms->ms_screen, y + ms->ms_input_y, x); + (void) wrefresh(ms->ms_screen); +} + +/* Parse buf into a list of words, which will be placed in strings specified by + argv. Space for these strings must have already been allocated. + Only the first n characters of each word will be copied */ +Parse_words(buf, argv, n) +char *buf; +char *argv[]; +int n; +{ + char *start, *end; /* For sausage machine */ + int argc; + + start = buf; + for(argc = 0; argc < MAX_ARGC; argc++) { + while(isspace(*start)) start++; /* Kill whitespace */ + if(*start == '\0') break; /* Nothing left */ + /* Now find the end of the word */ + for(end = start; *end != '\0' && !isspace(*end); end++); + (void) strncpy(argv[argc], start, MIN(end - start, n)); /* Copy it */ + argv[argc][MIN(end - start, n-1)] = '\0'; /* Terminate */ + start = end; + } + return(argc); +} + +/* This is the internal form of Find_command, which recursively searches + for a menu_line with command command in the specified menu */ +/* It will search to a maximum depth of d */ +struct menu_line *find_command_from(c, m, d) +char *c; +struct menu *m; +int d; +{ + int line; + struct menu_line *maybe; + + if(d < 0) return((struct menu_line *) 0); /* Too deep! */ + for(line = 0; line < m->m_length; line++) { + if(!strcmp(c, m->m_lines[line].ml_command)) { + return(&m->m_lines[line]); + } else if(m->m_lines[line].ml_submenu != NULLMENU + && (maybe = + find_command_from(c, m->m_lines[line].ml_submenu, d-1)) + != (struct menu_line *) 0) { + return(maybe); + } + } + /* If we got to here, nothing works */ + return((struct menu_line *) 0); } + +/* Find_command searches down the current menu tree */ +/* And returns a pointer to a menu_line with the specified command name */ +/* It returns (struct menu_line *) 0 if none is found */ +struct menu_line *Find_command(command) +char *command; +{ + if(top_menu == NULLMENU) { + return((struct menu_line *) 0); + } else { + return(find_command_from(command, top_menu, MAX_MENU_DEPTH)); + } +} + +/* + * Local Variables: + * mode: c + * c-indent-level: 4 + * c-continued-statement-offset: 4 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * End: + */ -- 2.45.2