* $Source$
* $Author$
* $Header$
- * $Log$
- * Revision 1.6 1987-08-17 11:55:23 jtkohl
- * changes made by poto. Looks like cleanup
- *
- * Revision 1.5 87/08/07 18:09:46 poto
- * will not enter menu if ->m_entry returns DM_QUIT;
- * the command args from a submenu command will be passed on to ->m_entry();
- *
- * Revision 1.4 87/08/05 14:48:04 ambar
- * added latest set of hackery, to fix missing
- * newlines, and not being able to quit out of
- * the pager.
- *
- * Revision 1.3 87/08/03 05:10:34 wesommer
- * This one appears to work.
- *
- * Revision 1.2 87/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.
*
#endif lint
+#include <mit-copyright.h>
+#include <sys/types.h>
#include <stdio.h>
+#include <string.h>
#include <signal.h>
#include <curses.h>
+#ifdef POSIX
+#include <unistd.h>
+#include <termios.h>
+#endif /* POSIX */
#include <ctype.h>
+#ifndef sun
+#include <varargs.h>
+#endif
+#include <com_err.h>
+#include <moira.h>
#include "menu.h"
+#ifndef __STDC__
+#define const
+#endif
+
#define MAX(A,B) ((A) > (B) ? (A) : (B))
#define MIN(A,B) ((A) < (B) ? (A) : (B))
#define CTL(ch) ((ch) & 037)
#define MIN_INPUT 2 /* Minimum number of lines for input window */
-char *strcpy();
-char *strncpy();
+extern int interrupt; /* will be set if ^C is received */
+extern FILE *fdopen();
+#ifndef sgi
+extern int getpid();
+#endif
+extern char *calloc();
+extern char *whoami;
+
+FILE *log_file = (FILE *) NULL; /* file stream of log file */
int more_flg = 1;
+#ifdef POSIX
+extern char *malloc();
+#endif
+
/* Structure for holding current displayed menu */
struct menu_screen {
WINDOW *ms_screen; /* Window for this menu */
#define NULLMS ((struct menu_screen *) 0)
Menu *top_menu; /* Root for command search */
+int parsed_argc; /* used by extern routines to get additional */
+char **parsed_argv; /* comand line input */
+
+/*
+ * Hook function to cause error messages to be printed through
+ * curses instead of around it. Takes at most 5 args to the
+ * printf string (crock...)
+ */
+
+void
+menu_com_err_hook(who, code, fmt, arg1, arg2, arg3, arg4, arg5)
+ const char *who;
+ long code;
+ const char *fmt;
+ caddr_t arg1, arg2, arg3, arg4, arg5;
+{
+ char buf[BUFSIZ], *cp;
+
+ (void) strcpy(buf, who);
+ for (cp = buf; *cp; cp++);
+ *cp++ = ':';
+ *cp++ = ' ';
+ if (code) {
+ (void) strcpy(cp, error_message(code));
+ while (*cp)
+ cp++;
+ }
+ sprintf(cp, fmt, arg1, arg2, arg3, arg4, arg5);
+ Put_message(buf);
+}
/*
* Start_menu takes a menu as an argument. It initializes curses u.s.w.,
Menu *m;
{
struct menu_screen *make_ms();
-
- if (initscr() == ERR) {
+#ifdef __STDC__
+ register void (*old_hook)(const char *, long, const char *, va_list) = set_com_err_hook(menu_com_err_hook);
+#else
+ register void (*old_hook)() = set_com_err_hook(menu_com_err_hook);
+#endif
+
+ if (initscr() == (WINDOW *)ERR) {
fputs("Can't initialize curses!\n", stderr);
Start_no_menu(m);
- }
- raw(); /* We parse & print everything ourselves */
- noecho();
- cur_ms = make_ms(0); /* So we always have some current */
+ } else {
+ (void) raw(); /* We parse & print everything ourselves */
+ (void) noecho();
+ cur_ms = make_ms(0); /* So we always have some current */
/* menu_screen */
- top_menu = m;
- /* Run the menu */
- (void) Do_menu(m, -1, (char **) NULL);
+ /* Run the menu */
+ (void) Do_menu(m, -1, (char **) NULL);
+ }
+ (void) set_com_err_hook(old_hook);
Cleanup_menu();
}
Cleanup_menu()
{
if (cur_ms) {
- wclear(cur_ms->ms_screen);
- wrefresh(cur_ms->ms_screen);
+ (void) wclear(cur_ms->ms_screen);
+ (void) wrefresh(cur_ms->ms_screen);
}
endwin();
}
Menu *m;
{
cur_ms = NULLMS;
- top_menu = m;
+ COLS = 80;
/* Run the menu */
(void) Do_menu(m, -1, (char **) NULL);
}
int length;
{
struct menu_screen *ms;
- char *malloc();
if (MAX_TITLE + length + MIN_INPUT > LINES) {
fputs("Menu too big!\n", stderr);
int margc;
char *margv[];
{
- struct menu_screen *my_ms, *old_cur_ms;
+ struct menu_screen *my_ms = NULLMS, *old_cur_ms = NULLMS;
char argvals[MAX_ARGC][MAX_ARGLEN]; /* This is where args are stored */
char buf[MAX_ARGC * MAX_ARGLEN];
char *argv[MAX_ARGC];
struct menu_line *command, *Find_command();
int argc;
int quitflag, is_topmenu = (margc < 0);
+ int toggle_logging();
/* Entry function gets called with old menu_screen still current */
- if (m->m_entry != NULLFUNC)
+ if (m->m_entry != NULLFUNC) {
if (m->m_entry(m, margc, margv) == DM_QUIT)
return DM_NORMAL;
+ if (parsed_argc > 0) {
+ margc = parsed_argc + 1;
+ margv = --parsed_argv;
+ } else {
+ margc--;
+ margv++;
+ }
+ }
+
+ parsed_argc = 0;
/* 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 + 1 + (is_topmenu?0:1));
+ /* 2 is for the 2 obligatory lines; quit and toggle */
+ cur_ms = my_ms = make_ms(m->m_length + 2 + (is_topmenu ? 0 : 1));
/* Now print the title and the menu */
(void) wclear(my_ms->ms_menu);
(void) wstandend(my_ms->ms_title);
for (line = 0; line < m->m_length; line++) {
+ int len = strlen(m->m_lines[line].ml_command);
+ if (len > 12) len=12;
+
(void) wmove(my_ms->ms_menu, line, 0);
- (void) wprintw(my_ms->ms_menu, "%2d. (%-12s) %s.", line + 1,
+
+ (void) wprintw(my_ms->ms_menu, "%2d. (%s)%*s %s.", line + 1,
m->m_lines[line].ml_command,
+ 12-len, "",
m->m_lines[line].ml_doc);
}
(void) wmove(my_ms->ms_menu, line++, 0);
if (!is_topmenu) {
(void) waddstr(my_ms->ms_menu,
- " r. (return ) Return to previous menu.");
- (void) wmove(my_ms->ms_menu, line, 0);
+ " r. (return) Return to previous menu.");
+ (void) wmove(my_ms->ms_menu, line++, 0);
}
- (void) waddstr(my_ms->ms_menu, " q. (quit ) Quit.");
-
+ (void) waddstr(my_ms->ms_menu,
+ " t. (toggle) Toggle logging on and off.");
+ (void) wmove(my_ms->ms_menu, line, 0);
+ (void) waddstr(my_ms->ms_menu, " q. (quit) Quit.");
+ } else {
+ Put_message(m->m_title);
+ for (line = 0; line < m->m_length; line++) {
+ sprintf(buf, "%2d. (%s)%*s %s.", line + 1,
+ m->m_lines[line].ml_command,
+ 12 - strlen(m->m_lines[line].ml_command), "",
+ m->m_lines[line].ml_doc);
+ Put_message(buf);
+ }
+ if (!is_topmenu)
+ Put_message(" r. (return) Return to previous menu.");
+ Put_message(" t. (toggle) Toggle logging on and off.");
+ Put_message(" q. (quit) Quit.");
+ Put_message(" ?. Print this information.");
}
for (;;) {
/* This is here because we may be coming from another menu */
if (cur_ms != NULL)
touchwin(my_ms->ms_screen);
- /* Get a command */
- if (!Prompt_input("Command: ", buf, sizeof(buf)))
- continue;
- /* 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 (margc > 1) {
+ /* Initialize argv */
+ for (argc = 0; argc < MAX_ARGC; argc++)
+ argv[argc] = argvals[argc];
+ argc = margc - 1;
+ for (i = 1; i < margc; i++)
+ strcpy(argvals[i - 1], margv[i]);
+ margc = 0;
+ } else {
+ /* Get a command */
+ if (!Prompt_input("Command: ", buf, sizeof(buf))) {
+ if (cur_ms == NULLMS &&
+ feof(stdin))
+ sprintf(buf, "quit");
+ else
+ continue;
+ }
+ /* 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 ((!is_topmenu &&
- (!strcmp(argv[0], "r")
- || !strcmp(argv[0], "return")))
- || !strcmp(argv[0], "q")
- || !strcmp(argv[0], "quit")) {
+ (!strcmp(argv[0], "r") || !strcmp(argv[0], "return")))
+ || !strcmp(argv[0], "q") || !strcmp(argv[0], "quit")) {
+
/* here if it's either return or quit */
if (cur_ms != NULLMS) {
cur_ms = old_cur_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])) ==
+ else if (argv[0][0] == '?') {
+ for (line = 0; line < m->m_length; line++) {
+ sprintf(buf, "%2d. (%s)%*s %s.", line + 1,
+ m->m_lines[line].ml_command,
+ 12 - strlen(m->m_lines[line].ml_command), "",
+ m->m_lines[line].ml_doc);
+ Put_message(buf);
+ }
+ if (!is_topmenu)
+ Put_message(" r. (return) Return to previous menu.");
+ Put_message(" t. (toggle) Toggle logging on and off.");
+ Put_message(" q. (quit) Quit.");
+ continue;
+ }
+ else if (!strcmp(argv[0], "t") || !strcmp(argv[0], "toggle")) {
+ toggle_logging(argc, argv);
+ continue;
+ }
+ /* finally, try to find it using Find_command */
+ else if ((command = Find_command(m, argvals[0])) ==
(struct menu_line *) 0) {
- Put_message("Command not recognized");
+ sprintf(buf, "Command not recognized: %s\n", argvals[0]);
+ Put_message(buf);
continue;
}
/* If we got to here, command is a valid menu_line */
argvals[argc], sizeof(argvals[argc])))
goto punt_command;
}
+ parsed_argc = argc - command->ml_argc;
+ parsed_argv = &(argv[command->ml_argc]);
if (command->ml_function != NULLFUNC) {
/* If it's got a function, call it */
quitflag = command->ml_function(argc, argv);
}
if (m->m_exit != NULLFUNC)
m->m_exit(m);
+ parsed_argc = 0;
return (DM_QUIT);
}
punt_command:
- ;
+ parsed_argc = 0;
}
}
+refresh_screen()
+{
+ if (cur_ms != NULLMS) {
+ touchwin(cur_ms->ms_screen);
+ refresh_ms(cur_ms);
+ }
+}
+
+
/* Prompt the user for input in the input window of cur_ms */
int Prompt_input(prompt, buf, buflen)
char *prompt;
char *buf;
int buflen;
+{
+ int c;
+ char *p;
+ int y, x, oldx, oldy;
+
+ if (cur_ms != NULLMS) {
+ more_flg = 1;
+ getyx(cur_ms->ms_input, y, x);
+ (void) wmove(cur_ms->ms_input, y, 0);
+
+ refresh_screen();
+ (void) waddstr(cur_ms->ms_input, prompt);
+ getyx(cur_ms->ms_input, y, x);
+
+ oldx = x;
+ oldy = y;
+ p = buf;
+ while(1) {
+ (void) wmove(cur_ms->ms_input, y, x);
+ (void) touchwin(cur_ms->ms_screen);
+ (void) wclrtoeol(cur_ms->ms_input);
+ (void) wrefresh(cur_ms->ms_input);
+ c = getchar() & 0x7f;
+ switch (c) {
+ case CTL('C'):
+ *p = '\0';
+ return 0;
+ case CTL('Z'):
+ (void) kill(getpid(), SIGTSTP);
+ touchwin(curscr);
+ break;
+ case CTL('L'):
+ (void) wclear(cur_ms->ms_input);
+ (void) waddstr(cur_ms->ms_input, prompt);
+ (void) touchwin(cur_ms->ms_input);
+ (void) move(LINES - 1, 0);
+ (void) wrefresh(curscr);
+ getyx(cur_ms->ms_input, y, x);
+ oldy = y;
+ oldx = x;
+ p = buf;
+ break;
+
+ case '\n':
+ case '\r':
+ goto end_input;
+ /* these should be obtained by doing ioctl() on tty */
+ case '\b':
+ case '\177':
+ if (p > buf) {
+ p--;
+ x--;
+ if (x < 0) {
+ (void) wmove(cur_ms->ms_input, y, 0);
+ (void) wclrtoeol(cur_ms->ms_input);
+ y--;
+ x = cur_ms->ms_input->_maxx-1;
+ }
+ }
+ break;
+ case CTL('U'):
+ case CTL('G'):
+ case CTL('['):
+ x = oldx;
+ y = oldy;
+ p = buf;
+ break;
+ default:
+ /* (buflen - 1) leaves room for the \0 */
+ if (isprint(c) && (p - buf < buflen - 1)) {
+ (void) waddch(cur_ms->ms_input, c);
+ *p++ = c;
+ x++;
+ if (x >= cur_ms->ms_input->_maxx) {
+ x = 0;
+ y++;
+ }
+ } else
+ putchar(CTL('G'));
+ break;
+ }
+ }
+ end_input:
+ (void) waddch(cur_ms->ms_input, '\n');
+
+ (void) wclrtoeol(cur_ms->ms_input);
+ refresh_ms(cur_ms);
+ *p = '\0';
+ Start_paging();
+ goto gotit;
+ } else {
+ printf("%s", prompt);
+ if (gets(buf) == NULL)
+ return 0;
+ if (interrupt) {
+ interrupt = 0;
+ return 0;
+ }
+ Start_paging();
+ goto gotit;
+ }
+gotit:
+ strcpy(buf, strtrim(buf));
+ return 1;
+}
+
+/* Prompt the user for input in the input window of cur_ms, but don't echo
+ and allow some control characters */
+int Password_input(prompt, buf, buflen)
+ char *prompt;
+ char *buf;
+ int buflen;
{
int c;
char *p;
(void) wmove(cur_ms->ms_input, y, x);
(void) wclrtoeol(cur_ms->ms_input);
refresh_ms(cur_ms);
- c = getchar();
+ c = getchar() & 0x7f;
switch (c) {
case CTL('C'):
return 0;
case CTL('Z'):
- kill(getpid(), SIGTSTP);
+ (void) kill(getpid(), SIGTSTP);
touchwin(curscr);
break;
case CTL('L'):
(void) wclear(cur_ms->ms_input);
(void) waddstr(cur_ms->ms_input, prompt);
- wrefresh(curscr);
+ refresh_ms(cur_ms);
+ (void) move(LINES - 1, 0);
+ (void) wrefresh(curscr);
getyx(cur_ms->ms_input, y, x);
break;
case '\n':
case '\r':
(void) waddch(cur_ms->ms_input, '\n');
- (void) waddch(cur_ms->ms_input, '\r');
(void) wclrtoeol(cur_ms->ms_input);
refresh_ms(cur_ms);
}
break;
case CTL('U'):
- case CTL('G'):
- case CTL('['):
x = oldx;
p = buf;
break;
default:
- if (isprint(c)) {
- (void) waddch(cur_ms->ms_input, c);
- *p++ = c;
- x++;
- } else
- putchar(CTL('G'));
+ *p++ = c;
break;
}
}
}
else {
+#ifdef POSIX
+ struct termios ttybuf, nttybuf;
+#else
+ struct sgttyb ttybuf, nttybuf;
+#endif /* POSIX */
printf("%s", prompt);
- if (gets(buf) == NULL)
+ /* turn off echoing */
+#ifdef POSIX
+ tcgetattr(0, &ttybuf);
+ nttybuf = ttybuf;
+ nttybuf.c_lflag &= ~ECHO;
+ tcsetattr(0, TCSANOW, &nttybuf);
+ if (gets(buf) == NULL) {
+ tcsetattr(0, TCSANOW, &ttybuf);
+ putchar('\n');
+ return 0;
+ }
+ putchar('\n');
+ (void) ioctl(0, TCSETA, (char *)&ttybuf);
+#else
+ (void) ioctl(0, TIOCGETP, (char *)&ttybuf);
+ nttybuf = ttybuf;
+ nttybuf.sg_flags &= ~ECHO;
+ (void)ioctl(0, TIOCSETP, (char *)&nttybuf);
+ if (gets(buf) == NULL) {
+ (void) ioctl(0, TIOCSETP, (char *)&ttybuf);
+ putchar('\n');
return 0;
+ }
+ putchar('\n');
+ (void) ioctl(0, TIOCSETP, (char *)&ttybuf);
+#endif /* POSIX */
Start_paging();
return 1;
}
+ return 0;
}
int lines_left;
lines_left = -1;
}
-/* Print a message in the input window of cur_ms */
+/* Print a message in the input window of cur_ms. */
Put_message(msg)
- char *msg;
+char *msg;
+{
+ char *copy, *line, *s;
+
+ copy = (char *) malloc((u_int)COLS);
+ s = line = msg;
+ if (log_file) { /* if we're doing logging; we assume that the */
+ /* file has already been opened. */
+ (void) fprintf(log_file, "%s\n", msg);
+ fflush(log_file);
+ }
+
+ while(*s++) {
+ if (s - line >= COLS-1) {
+ (void) strncpy(copy, line, COLS-1);
+ line += COLS-1;
+ } else if (*s == '\n') {
+ *s = '\0';
+ (void) strcpy(copy, line);
+ line = ++s;
+ } else
+ continue;
+ Put_line(copy);
+ }
+ Put_line(line);
+ free(copy);
+}
+
+/* Will be truncated to COLS characters. */
+Put_line(msg)
+char *msg;
{
int y, x, i;
char *msg1, chr;
(void) wprintw(cur_ms->ms_input, "---More---");
(void) wstandend(cur_ms->ms_input);
refresh_ms(cur_ms);
- chr = getchar();/* We do care what it is */
- if (chr == 'q' || chr == 'Q') {
+ chr = getchar() & 0x7f;/* We do care what it is */
+ if (chr == 'q' || chr == 'Q' || chr == 3 /* ^C */) {
more_flg = 0;
return;
}
getyx(cur_ms->ms_input, y, x);
+ /* x is a bitbucket; avoid lint problems */
+ x=x;
(void) wmove(cur_ms->ms_input, y, 0);
(void) wclrtoeol(cur_ms->ms_input);
}
else {
printf("---More (hit return)---");
- (void) getchar();
+ getchar();
}
Start_paging(); /* Reset lines_left */
}
}
if (cur_ms != NULLMS) {
- msg1 = (char *) calloc(COLS, 1);
- (void) strcpy(msg1, msg);
- for (i = strlen(msg); i < COLS - 1; i++)
+ msg1 = (char *) calloc((u_int)COLS, 1);
+ (void) strncpy(msg1, msg, COLS-1);
+ for (i = strlen(msg1); i < COLS - 1; i++)
msg1[i] = ' ';
(void) wprintw(cur_ms->ms_input, "%s\n", msg1);
-/* refresh_ms(cur_ms); */
}
else {
puts(msg);
refresh_ms(ms)
struct menu_screen *ms;
{
- int y, x;
-
- getyx(ms->ms_input, y, x);
- (void) wmove(ms->ms_screen, y + ms->ms_input_y, x);
- (void) wrefresh(ms->ms_screen);
+ (void) wrefresh(ms->ms_title);
+ (void) wrefresh(ms->ms_menu);
+ (void) wrefresh(ms->ms_input);
}
/* Parse buf into a list of words, which will be placed in strings specified by
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) {
+ }
+ for (line = 0; line < m->m_length; line++) {
+ 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);
}
}
/* 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)
+Find_command(m, command)
+ Menu *m;
char *command;
{
- if (top_menu == NULLMENU) {
+ if (m == NULLMENU) {
return ((struct menu_line *) 0);
}
else {
- return (find_command_from(command, top_menu, MAX_MENU_DEPTH));
+ return (find_command_from(command, m, 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:
- */
+/*ARGSUSED*/
+int
+toggle_logging(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int pid;
+ char buf[BUFSIZ];
+
+ if (log_file == (FILE *) NULL) {
+ pid = getpid();
+ if (!whoami) {
+ Put_message("I've lost my SENSE of DIRECTION! I have no IDEA who I AM!");
+ Put_message("My God... You've turned him into a DEMOCRAT!!");
+ Put_message(" -- Doonesbury");
+ Put_message("");
+ Put_message("translation: your log file can be found in \"/usr/tmp/a.out.pid\".");
+ whoami = "a.out";
+ (void) sprintf(buf, "/usr/tmp/%s-log.%d", whoami, pid);
+ }
+ else
+ (void) sprintf(buf, "/usr/tmp/%s-log.%d", whoami, pid);
+
+ /* open the file */
+ log_file = fopen(buf,"a");
+
+ if (log_file == (FILE *) NULL)
+ Put_message("Open of log file failed. Logging is not on.");
+ else
+ Put_message("Log file successfully opened.");
+ }
+ else { /* log_file is a valid pointer; turn off logging. */
+ (void) fflush(log_file);
+ (void) fclose(log_file);
+ log_file = (FILE *) NULL;
+ Put_message("Logging off.");
+ }
+ return(DM_NORMAL);
+}