-/*
- * Copyright 1987 by the Massachusetts Institute of Technology.
- * For copying and distribution information, see the file
- * "mit-copyright.h".
- *
- * $Source$
- * $Author$
- * $Header$
+/* $Id$
*
* Generic menu system module.
*
- * Basically, we define an enormous tree structure which represents the
- * menu. Some extra pieces (ml_command, ma_doc) get thrown in so we can
- * also use the structure for a command-based system.
- *
- * By making the menu descriptions so general, we can ease porting to just
- * about anything.
+ * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology.
+ * For copying and distribution information, see the file
+ * <mit-copyright.h>.
*/
-#ifndef lint
-static char rcsid_menu_c[] = "$Header$";
-#endif
-
#include <mit-copyright.h>
-#include <sys/types.h>
+#include <moira.h>
+#include "menu.h"
+
+#include <ctype.h>
+#ifdef HAVE_CURSES
+#include <curses.h>
+#endif
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <signal.h>
-#include <curses.h>
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
-#include <termios.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <com_err.h>
-#include <moira.h>
-#include "menu.h"
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#include <conio.h>
+#include <process.h>
+#ifdef getchar
+#undef getchar
+#endif
+#define getchar() _getch()
+#define getpid _getpid
+#endif /* _WIN32 */
+RCSID("$Header$");
+
+#ifdef MAX
+#undef MAX
+#undef MIN
+#endif
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define CTL(ch) ((ch) & 037)
/* Structure for holding current displayed menu */
struct menu_screen {
+#ifdef HAVE_CURSES
WINDOW *ms_screen; /* Window for this menu */
WINDOW *ms_title; /* Title subwindow */
WINDOW *ms_menu; /* Menu subwindow */
WINDOW *ms_input; /* Input subwindow */
+#endif /* HAVE_CURSES */
int ms_input_y; /* Input subwindow reference coordinate */
} *cur_ms;
+#ifndef HAVE_CURSES
+int COLS;
+#endif
+
#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 */
+int Parse_words(char *buf, char *argv[], int n);
+void refresh_ms(struct menu_screen *ms);
+void Put_line(char *msg);
+void menu_com_err_hook(const char *who, long code,
+ const char *fmt, va_list ap);
+struct menu_screen *make_ms(int length);
+void destroy_ms(struct menu_screen *ms);
+struct menu_line *find_command_from(char *c, struct menu *m, int d);
+struct menu_line *Find_command(Menu *m, char *command);
+int toggle_logging(int argc, char *argv[]);
+
/*
* 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...)
+ * curses instead of around it.
*/
-void menu_com_err_hook(const char *who, long code, const char *fmt,
- caddr_t arg1, caddr_t arg2, caddr_t arg3,
- caddr_t arg4, caddr_t arg5)
+void menu_com_err_hook(const char *who, long code, const char *fmt, va_list ap)
{
char buf[BUFSIZ], *cp;
- strcpy(buf, who);
- for (cp = buf; *cp; cp++)
- ;
- *cp++ = ':';
- *cp++ = ' ';
+ if (who)
+ {
+ strcpy(buf, who);
+ for (cp = buf; *cp; cp++)
+ ;
+ *cp++ = ':';
+ *cp++ = ' ';
+ }
+ else
+ {
+ cp = buf;
+ *cp = '\0';
+ }
if (code)
{
strcpy(cp, error_message(code));
while (*cp)
cp++;
}
- sprintf(cp, fmt, arg1, arg2, arg3, arg4, arg5);
+ vsprintf(cp, fmt, ap);
Put_message(buf);
}
+#ifdef HAVE_CURSES
/*
* 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,
* if user functions which run their own menus don't cooperate.)
* Start_menu should only be called once, at the start of the program.
*/
-int Start_menu(Menu *m)
+void Start_menu(Menu *m)
{
- struct menu_screen *make_ms();
- register void (*old_hook)(const char *, long, const char *, va_list) =
- set_com_err_hook((void (*) (const char *, long, const char *, va_list))menu_com_err_hook);
-
- if (initscr() == (WINDOW *)ERR)
+ void (*old_hook)(const char *, long, const char *, va_list) =
+ set_com_err_hook(menu_com_err_hook);
+#ifdef CURSES_HAS_NEWTERM
+ SCREEN *scrn = newterm(NULL, stdout, stdin);
+#else
+ WINDOW *scrn = initscr();
+#endif
+ if (!scrn)
{
- fputs("Can't initialize curses!\n", stderr);
+ fputs("Can't initialize curses!\nReverting to -nomenu mode\n\n", stderr);
Start_no_menu(m);
}
else
{
+#ifdef CURSES_HAS_NEWTERM
+ set_term(scrn);
+ endwin();
+ initscr();
+#endif
raw(); /* We parse & print everything ourselves */
noecho();
cur_ms = make_ms(0); /* So we always have some current */
/* menu_screen */
/* Run the menu */
Do_menu(m, -1, NULL);
+ Cleanup_menu();
}
set_com_err_hook(old_hook);
- Cleanup_menu();
}
-int Cleanup_menu(void)
+void Cleanup_menu(void)
{
if (cur_ms)
{
wclear(cur_ms->ms_screen);
wrefresh(cur_ms->ms_screen);
+ endwin();
}
- endwin();
-}
-
-
-/* Like Start_menu, except it doesn't print menus and doesn't use curses */
-int Start_no_menu(Menu *m)
-{
- cur_ms = NULLMS;
- COLS = 80;
- /* Run the menu */
- Do_menu(m, -1, NULL);
}
/*
/*
* This routine destroys a menu_screen.
*/
-int destroy_ms(struct menu_screen *ms)
+void destroy_ms(struct menu_screen *ms)
{
delwin(ms->ms_title);
delwin(ms->ms_menu);
delwin(ms->ms_screen);
free(ms);
}
+#endif /* HAVE_CURSES */
+
+/* Like Start_menu, except it doesn't print menus and doesn't use curses */
+void Start_no_menu(Menu *m)
+{
+ cur_ms = NULLMS;
+ COLS = 80;
+ /* Run the menu */
+ Do_menu(m, -1, NULL);
+}
/*
* This guy actually puts up the menu
char *argv[MAX_ARGC];
int line;
int i;
- struct menu_line *command, *Find_command();
+ struct menu_line *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)
parsed_argc = 0;
+#ifdef HAVE_CURSES
/* The following get run only in curses mode */
if (cur_ms != NULLMS)
{
/* Now print the title and the menu */
wclear(my_ms->ms_screen);
wrefresh(my_ms->ms_screen);
- wmove(my_ms->ms_title, 0, MAX(0, (COLS - strlen(m->m_title)) >> 1));
+ wmove(my_ms->ms_title, 0, MAX(0, (COLS - (int)strlen(m->m_title)) >> 1));
wstandout(my_ms->ms_title);
waddstr(my_ms->ms_title, m->m_title);
wstandend(my_ms->ms_title);
waddstr(my_ms->ms_menu, " q. (quit) Quit.");
}
else
+#endif /* HAVE_CURSES */
{
Put_message(m->m_title);
for (line = 0; line < m->m_length; line++)
{
/* This will be set by a return val from func or submenu */
quitflag = DM_NORMAL;
+#ifdef HAVE_CURSES
/* This is here because we may be coming from another menu */
if (cur_ms != NULL)
{
touchwin(my_ms->ms_screen);
wrefresh(my_ms->ms_screen);
}
+#endif /* HAVE_CURSES */
if (margc > 1)
{
/* Initialize argv */
!strcmp(argv[0], "q") || !strcmp(argv[0], "quit"))
{
/* here if it's either return or quit */
+#ifdef HAVE_CURSES
if (cur_ms != NULLMS)
{
cur_ms = old_cur_ms;
destroy_ms(my_ms);
}
+#endif /* HAVE_CURSES */
if (m->m_exit != NULLFUNC)
m->m_exit(m);
return *argv[0] == 'r' ? DM_NORMAL : DM_QUIT;
}
if (quitflag == DM_QUIT)
{
+#ifdef HAVE_CURSES
if (cur_ms != NULLMS)
{
cur_ms = old_cur_ms;
destroy_ms(my_ms);
}
+#endif /* HAVE_CURSES */
if (m->m_exit != NULLFUNC)
m->m_exit(m);
parsed_argc = 0;
}
}
-int refresh_screen(void)
+void refresh_screen(void)
{
+#ifdef HAVE_CURSES
if (cur_ms != NULLMS)
{
touchwin(cur_ms->ms_screen);
refresh_ms(cur_ms);
}
+#endif /* HAVE_CURSES */
}
/* Prompt the user for input in the input window of cur_ms */
int Prompt_input(char *prompt, char *buf, int buflen)
{
+#ifdef HAVE_CURSES
int c;
char *p;
int y, x, oldx, oldy;
wmove(cur_ms->ms_input, y, 0);
wclrtoeol(cur_ms->ms_input);
y--;
-#ifdef __NetBSD__
- x = cur_ms->ms_input->maxx - 1;
-#else
- x = cur_ms->ms_input->_maxx - 1;
-#endif
+ x = getmaxx(cur_ms->ms_input) - 1;
}
}
break;
waddch(cur_ms->ms_input, c);
*p++ = c;
x++;
-#ifdef __NetBSD__
- if (x >= cur_ms->ms_input->maxx)
-#else
- if (x >= cur_ms->ms_input->_maxx)
-#endif
+ if (x >= getmaxx(cur_ms->ms_input))
{
x = 0;
y++;
refresh_ms(cur_ms);
*p = '\0';
Start_paging();
- goto gotit;
+ strcpy(buf, strtrim(buf));
+ return 1;
}
else
+#endif /* HAVE_CURSES */
{
+ char bigbuf[BUFSIZ];
+
printf("%s", prompt);
- if (!fgets(buf, buflen, stdin))
+ if (!fgets(bigbuf, BUFSIZ, stdin))
return 0;
if (interrupt)
{
return 0;
}
Start_paging();
- goto gotit;
+ strncpy(buf, strtrim(bigbuf), buflen);
+ if (strchr(buf, '\n'))
+ *strchr(buf, '\n') = '\0';
+ else
+ buf[buflen - 1] = '\0';
+ return 1;
}
-gotit:
- strcpy(buf, strtrim(buf));
- return 1;
}
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 */
-int Start_paging(void)
+void Start_paging(void)
{
+#ifdef HAVE_CURSES
if (cur_ms != NULLMS)
lines_left = LINES - cur_ms->ms_input_y - 1;
else
+#endif /* HAVE_CURSES */
lines_left = 23;
}
/* Turn off paging */
-int Stop_paging(void)
+void Stop_paging(void)
{
lines_left = -1;
}
/* Print a message in the input window of cur_ms. */
-int Put_message(char *msg)
+void Put_message(char *msg)
{
char *copy, *line, *s;
}
/* Will be truncated to COLS characters. */
-int Put_line(char *msg)
+void Put_line(char *msg)
{
- int y, x, i;
- char *msg1, chr;
-
if (!more_flg)
return;
if (--lines_left == 0)
{
/* Give the user a more prompt */
+#ifdef HAVE_CURSES
if (cur_ms != NULLMS)
{
+ int x, y;
+ char chr;
+
wstandout(cur_ms->ms_input);
wprintw(cur_ms->ms_input, "---More---");
wstandend(cur_ms->ms_input);
wclrtoeol(cur_ms->ms_input);
}
else
+#endif /* HAVE_CURSES */
{
printf("---More (hit return)---");
getchar();
}
}
+#ifdef HAVE_CURSES
if (cur_ms != NULLMS)
{
+ int i;
+ char *msg1;
+
msg1 = calloc(COLS, 1);
strncpy(msg1, msg, COLS - 1);
for (i = strlen(msg1); i < COLS - 1; i++)
wprintw(cur_ms->ms_input, "%s\n", msg1);
}
else
+#endif /* HAVE_CURSES */
puts(msg);
}
+#ifdef HAVE_CURSES
/* Refresh a menu_screen onto the real screen */
-int refresh_ms(struct menu_screen *ms)
+void refresh_ms(struct menu_screen *ms)
{
wrefresh(ms->ms_title);
wrefresh(ms->ms_menu);
wrefresh(ms->ms_input);
}
+#endif /* HAVE_CURSES */
/* 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.
return find_command_from(command, m, MAX_MENU_DEPTH);
}
+static char *get_tmp_dir(void)
+{
+#ifdef _WIN32
+ static char tmp[BUFSIZ];
+ DWORD len;
+ if (!tmp[0])
+ {
+ len = GetTempPath(sizeof(tmp), tmp);
+ if (!len || (len > sizeof(tmp)))
+ strcpy(tmp, ".");
+ }
+ return tmp;
+#else
+ return "/var/tmp";
+#endif
+}
+
int toggle_logging(int argc, char *argv[])
{
- int pid;
char buf[BUFSIZ];
if (!log_file)
{
- 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";
- sprintf(buf, "/usr/tmp/%s-log.%d", whoami, pid);
- }
- else
- sprintf(buf, "/usr/tmp/%s-log.%d", whoami, pid);
+ sprintf(buf, "%s/%s-log.%ld", get_tmp_dir(), whoami, (long)getpid());
/* open the file */
log_file = fopen(buf, "a");