home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume27
/
ytalk-3.0
/
part01
/
menu.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-20
|
19KB
|
900 lines
/* menu.c */
/* NOTICE
*
* Copyright (c) 1990,1992,1993 Britt Yenne. All rights reserved.
*
* This software is provided AS-IS. The author gives no warranty,
* real or assumed, and takes no responsibility whatsoever for any
* use or misuse of this software, or any damage created by its use
* or misuse.
*
* This software may be freely copied and distributed provided that
* no part of this NOTICE is deleted or edited in any manner.
*
*/
/* Mail comments or questions to ytalk@austin.eds.com */
#include "header.h"
#include <fcntl.h>
#include "menu.h"
/* This particular file was written real early one night (morning?)
* while trying to stay awake long enough to do laundry. I hereby take
* extra-special pains to absolve myself of any and all responsibility
* for this source.
*/
static void main_menu_sel();
menu_item *menu_ptr = NULL; /* current menu in processing */
static int menu_len; /* number of items in current menu */
static int menu_long; /* longest item of current menu */
static int menu_line; /* current line number of menu */
static int text_pos = -1; /* text offset if non-negative */
static int text_ypos = -1, text_xpos = -1; /* text coord if non-negative */
extern void raw_term(); /* our raw interface to the terminal */
/* some menus... */
static menu_item main_menu[] = {
{ "Main Menu", NULL, ' ' },
{ "", NULL, ' ' },
{ "add a user", main_menu_sel, 'a' },
{ "delete a user", main_menu_sel, 'd' },
{ "options", main_menu_sel, 'o' },
{ "shell", main_menu_sel, 's' },
{ "user list", main_menu_sel, 'u' },
{ "output user to file", main_menu_sel, 'w' },
{ "quit", main_menu_sel, 'q' },
{ "", NULL, '\0'} /* MUST BE LAST */
};
#define MAXUMENU 52
static menu_item user_menu[MAXUMENU]; /* this one changes each time */
static menu_item option_menu[20]; /* options menu buffer */
static menu_item yes_no_menu[1]; /* yes/no entry menu */
static menu_item mesg_menu[1]; /* message menu */
static char text_str[MAXTEXT+1]; /* string entry buffer */
static menu_item text_menu[2]; /* string entry menu */
static char user_buf[MAXUMENU][80]; /* user list buffers */
/* major hack below... [maniacal laughter] */
static int got_error = 0;
static char err_str[8][MAXERR];
static menu_item error_menu[] = {
{ "Ytalk Error", NULL, ' ' },
{ "", NULL, ' ' },
{ NULL, show_error, ' ' },
{ NULL, show_error, ' ' },
{ "", NULL, ' ' },
{ NULL, show_error, ' ' },
{ NULL, show_error, ' ' },
{ "", NULL, ' ' },
{ NULL, show_error, ' ' },
{ NULL, show_error, ' ' },
{ "", NULL, ' ' },
{ NULL, show_error, ' ' },
{ NULL, show_error, ' ' },
{ "", NULL, '\0'} /* MUST BE LAST */
};
/* ---- local functions ---- */
static yuser *output_user = NULL;
static void
do_output(filename)
char *filename;
{
int fd;
if(output_user == NULL)
return;
if((fd = open(filename, O_RDWR | O_TRUNC | O_CREAT, 0600)) < 0)
{
show_error(filename);
return;
}
output_user->output_fd = fd;
spew_term(output_user, fd, output_user->rows, output_user->cols);
output_user = NULL;
}
static void
do_output_user(user)
yuser *user;
{
/* if he has an open descriptor, close it */
if(user->output_fd > 0)
{
close(user->output_fd);
user->output_fd = 0;
if(show_mesg("Output Terminated", NULL) >= 0)
update_menu();
return;
}
/* else open one */
output_user = user;
if(show_text("Output filename?", do_output) >= 0)
update_menu();
else
output_user = NULL;
}
static void
do_invite(name)
char *name;
{
invite(name, 1);
}
static void
main_menu_sel(key)
ychar key;
{
switch(key)
{
case 'a': /* add a user */
if(show_text("Add Which User?", do_invite) >= 0)
update_menu();
break;
case 'd': /* delete a user */
if(show_user_menu("Delete Which User?", free_user) >= 0)
update_menu();
break;
case 'o': /* show options */
if(show_option_menu() >= 0)
update_menu();
break;
case 's': /* invoke a shell */
kill_menu();
execute(NULL);
break;
case 'u': /* show a user list */
if(show_user_list() >= 0)
update_menu();
break;
case 'w': /* output user to file */
if(show_user_menu("Output Which User?", do_output_user) >= 0)
update_menu();
break;
case 'q': /* quit */
bail(0);
}
}
static void
option_menu_sel(key)
ychar key;
{
register yuser *u;
u_long old_flags;
old_flags = def_flags;
switch(key)
{
case 's': /* toggle scrolling */
def_flags ^= FL_SCROLL;
break;
case 'w': /* toggle word wrap */
def_flags ^= FL_WRAP;
break;
case 'i': /* toggle automatic imports */
def_flags ^= FL_IMPORT;
break;
case 'v': /* toggle automatic invitations */
def_flags ^= FL_INVITE;
break;
case 'r': /* toggle automatic re-rings */
def_flags ^= FL_RING;
break;
}
if(old_flags != def_flags)
{
for(u = user_list; u != NULL; u = u->unext)
if(!(u->flags & FL_LOCKED))
u->flags = def_flags;
}
if(show_option_menu() >= 0)
update_menu();
else
kill_menu();
}
static void
user_menu_sel(key)
ychar key;
{
register int i;
register yuser *u;
/* Remember... the user list could have changed between the time
* I created the user menu and the time I just now selected one
* of the users from it.
*/
for(i = 0; i < menu_len; i++)
if(user_menu[i].key == key)
{
for(u = user_list; u; u = u->unext)
if(u->key == key
&& strcmp(u->full_name, user_menu[i].item) == 0)
{
user_menu[0].func(u);
break;
}
break;
}
if(menu_ptr == user_menu)
kill_menu();
}
#define MENU_EXTRA 7 /* number of extra characters per menu screen item */
static void
generate_text_length()
{
menu_long = me->t_cols - MENU_EXTRA - 2;
if(menu_long < 5 || menu_long > MAXTEXT)
menu_long = MAXTEXT;
}
static void
generate_yes_no_length()
{
menu_long = strlen(yes_no_menu[0].item) - 2;
}
static void
pad_str(from, len, to)
char *from, *to;
int len;
{
for(; len > 0 && *from; len--, from++)
*(to++) = *from;
for(; len > 0; len--)
*(to++) = ' ';
*to = '\0';
}
/* ---- global functions ---- */
/* End any menu processing.
*/
void
kill_menu()
{
register int i;
if(menu_ptr != NULL)
{
menu_ptr = NULL;
redraw_term(me, 0);
flush_term(me);
text_pos = -1;
text_ypos = -1;
text_xpos = -1;
}
if(got_error)
{
got_error = 0;
for(i = 0; error_menu[i].key != '\0'; i++)
if(error_menu[i].func != NULL)
error_menu[i].item = NULL;
}
}
/* Update menu information.
*/
void
update_menu()
{
register ychar *c;
register char *d;
register int j, i, y, x;
static ychar *buf = NULL;
static int buflen = 0;
if(menu_ptr == NULL)
return;
/* process any input */
if(io_len > 0)
{
ychar ic;
if(menu_ptr == text_menu)
{
for(; io_len > 0; io_len--)
{
ic = *(io_ptr++);
if(ic > ' ' && ic <= '~')
{
if(text_pos >= menu_long)
putc(7, stderr);
else
{
text_str[text_pos] = (char)ic;
if(text_ypos >= 0)
raw_term(me, text_ypos, text_xpos + text_pos,
text_str + text_pos, 1);
text_str[++text_pos] = '\0';
}
}
else if(ic == me->old_rub)
{
if(text_pos > 0)
{
text_str[--text_pos] = '\0';
if(text_ypos >= 0)
raw_term(me, text_ypos, text_xpos + text_pos,
" ", 1);
}
}
else if(ic == me->KILL || ic == me->WORD)
{
if(text_pos > 0)
{
text_str[0] = '\0';
text_pos = 0;
if(text_ypos > 0)
raw_term(me, text_ypos, text_xpos,
" ", menu_long);
}
}
else if(ic == '\n' || ic == '\r')
{
if(text_pos > 0)
{
text_str[text_pos] = '\0'; /* just to be sure */
kill_menu();
text_menu[0].func(text_str);
}
else
kill_menu();
return;
}
else if(ic == 27 || ic == 4)
{
kill_menu();
return;
}
}
if(text_ypos >= 0)
{
raw_term(me, text_ypos, text_xpos + text_pos, NULL, 0);
flush_term(me);
return;
}
}
else if(menu_ptr == yes_no_menu)
{
/* don't handle yes/no input here */
}
else if(menu_ptr == mesg_menu)
{
ic = *(io_ptr++);
io_len--;
kill_menu();
if(mesg_menu[0].func)
mesg_menu[0].func(ic);
return;
}
else
{
ic = *(io_ptr++);
io_len--;
if(ic == ' ' || ic == '\n' || ic == '\r')
{
/* scroll the menu */
menu_line += me->t_rows - 1;
if(menu_line >= menu_len)
{
kill_menu();
return;
}
i = menu_len - (me->t_rows - 1); /* last full screen */
if(i < menu_line)
menu_line = i;
}
else if(ic > ' ' && ic <= '~')
{
for(i = 0; i < menu_len; i++)
if(menu_ptr[i].key == ic && menu_ptr[i].func != NULL)
{
menu_ptr[i].func(ic);
/*
* THE WHOLE WORLD COULD BE DIFFERENT NOW.
*/
i = -1;
break;
}
if(i >= 0)
kill_menu();
return;
}
else
{
kill_menu();
return;
}
}
}
/* Check the buffer. Keep in mind that we could be here because
* the window size has changed.
*/
if(menu_ptr == text_menu)
{
generate_text_length();
text_ypos = -1; /* assume it's not displayed */
text_xpos = -1;
}
else if(menu_ptr == yes_no_menu)
{
menu_len = 1;
menu_line = 0;
generate_yes_no_length();
}
if(menu_long > buflen)
{
buflen = menu_long + 64;
buf = (ychar *)realloc_mem(buf, buflen + MENU_EXTRA);
}
/* get starting X and Y coord */
x = center(me->t_cols, menu_long + MENU_EXTRA);
if(menu_line == 0)
{
if(menu_len + 2 <= me->t_rows)
{
y = center(me->t_rows, menu_len + 2);
raw_term(me, y++, x, "#####", menu_long + MENU_EXTRA);
}
else
y = 0;
}
else
y = 0;
/* show as many menu lines as we can */
for(i = menu_line; y+1 < me->t_rows && i < menu_len; i++, y++)
{
c = buf;
*(c++) = '#';
*(c++) = ' ';
if(menu_ptr[i].key == ' ')
{
j = 0;
if(menu_ptr == text_menu)
{
if(i > 0)
{
*(c++) = '>';
*(c++) = ' ';
j += 2;
text_ypos = y;
text_xpos = x + j + 2;
}
}
else if(menu_ptr != yes_no_menu)
{
int temp;
temp = center(menu_long + 3, strlen(menu_ptr[i].item));
for(; j < temp; j++)
*(c++) = ' ';
}
for(d = menu_ptr[i].item; *d; d++, j++)
*(c++) = (ychar)*d;
for(; j < menu_long + 3; j++)
*(c++) = ' ';
}
else
{
*(c++) = menu_ptr[i].key;
*(c++) = ':';
*(c++) = ' ';
for(d = menu_ptr[i].item, j = 0; *d; d++, j++)
*(c++) = (ychar)*d;
for(; j < menu_long; j++)
*(c++) = ' ';
}
*(c++) = ' ';
*(c++) = '#';
raw_term(me, y, x, buf, c - buf);
}
if(y < me->t_rows)
{
if(i < menu_len)
{
c = buf;
*(c++) = '#';
*(c++) = ' ';
*(c++) = ' ';
*(c++) = ' ';
*(c++) = ' ';
for(d = "(more)", j = 0; *d; d++, j++)
*(c++) = (ychar)*d;
for(; j < menu_long; j++)
*(c++) = ' ';
*(c++) = ' ';
*(c++) = '#';
raw_term(me, y, x, buf, c - buf);
raw_term(me, y, x + 12, NULL, 0);
}
else
{
raw_term(me, y, x, "#####", menu_long + MENU_EXTRA);
if(menu_ptr == text_menu)
raw_term(me, text_ypos, text_xpos + text_pos, NULL, 0);
else if(menu_ptr == yes_no_menu)
raw_term(me, y-1, x + menu_long + MENU_EXTRA - 2, NULL, 0);
else
raw_term(me, y, me->t_cols / 2, NULL, 0);
}
}
flush_term(me);
}
/* Show a menu, overriding any existing menu.
*/
int
show_menu(menu, len)
menu_item *menu;
int len;
{
register int i, j;
if(me->t_rows < 2)
{
show_error("show_menu: window too small");
return -1;
}
/* scan the menu for problems */
menu_long = 0;
for(i = 0; i < len; i++)
{
if((j = strlen(menu[i].item)) > menu_long)
menu_long = j;
if(menu[i].key < ' ' || menu[i].key >= '~')
{
show_error("show_menu: invalid key");
return -1;
}
}
if(menu_long <= 0)
{
show_error("show_menu: menu too small");
return -1;
}
if(menu_long < 10)
menu_long = 10;
/* set up the menu for display */
menu_ptr = menu;
menu_len = len;
menu_line = 0;
return 0;
}
/* Show a text entry menu, overriding any existing menu.
*/
int
show_text(prompt, func)
char *prompt;
void (*func)();
{
if(me->t_rows < 3)
{
show_error("show_text: window too small");
return -1;
}
/* set up the menu for display */
text_menu[0].item = prompt;
text_menu[0].func = func;
text_menu[0].key = ' ';
text_str[0] = '\0';
text_menu[1].item = text_str;
text_menu[1].func = NULL;
text_menu[1].key = ' ';
menu_ptr = text_menu;
menu_len = 2;
menu_line = 0;
text_ypos = -1;
text_xpos = -1;
text_pos = 0;
generate_text_length();
return 0;
}
/* Show a message in a menu.
*/
int
show_mesg(mesg, func)
char *mesg;
void (*func)();
{
/* set up the menu for display */
mesg_menu[0].item = mesg;
mesg_menu[0].func = func;
mesg_menu[0].key = ' ';
return show_menu(mesg_menu, 1);
}
int
show_main_menu()
{
static int main_items = 0;
if(main_items == 0)
{
while(main_menu[main_items].key != '\0')
main_items++;
}
return show_menu(main_menu, main_items);
}
int
show_option_menu()
{
register int i = 0;
option_menu[i].item = "Options Menu";
option_menu[i].func = NULL;
option_menu[i].key = ' ';
i++;
option_menu[i].item = "";
option_menu[i].func = NULL;
option_menu[i].key = ' ';
i++;
if(def_flags & FL_SCROLL)
option_menu[i].item = "turn scrolling off";
else
option_menu[i].item = "turn scrolling on";
option_menu[i].func = option_menu_sel;
option_menu[i].key = 's';
i++;
if(def_flags & FL_WRAP)
option_menu[i].item = "turn word-wrap off";
else
option_menu[i].item = "turn word-wrap on";
option_menu[i].func = option_menu_sel;
option_menu[i].key = 'w';
i++;
if(def_flags & FL_IMPORT)
option_menu[i].item = "turn auto-import off";
else
option_menu[i].item = "turn auto-import on";
option_menu[i].func = option_menu_sel;
option_menu[i].key = 'i';
i++;
if(def_flags & FL_INVITE)
option_menu[i].item = "turn auto-invite off";
else
option_menu[i].item = "turn auto-invite on";
option_menu[i].func = option_menu_sel;
option_menu[i].key = 'v';
i++;
if(def_flags & FL_RING)
option_menu[i].item = "turn auto-rering off";
else
option_menu[i].item = "turn auto-rering on";
option_menu[i].func = option_menu_sel;
option_menu[i].key = 'r';
i++;
return show_menu(option_menu, i);
}
int
show_user_menu(title, func)
char *title;
void (*func)();
{
register int i;
register yuser *u;
user_menu[0].item = title;
user_menu[0].func = func;
user_menu[0].key = ' ';
user_menu[1].item = "";
user_menu[1].func = NULL;
user_menu[1].key = ' ';
for(i = 2, u = user_list; u != NULL && i < MAXUMENU; u = u->unext)
if(u != me)
{
if(u->key != '\0')
{
strcpy(user_buf[i], u->full_name);
user_menu[i].item = user_buf[i];
user_menu[i].func = user_menu_sel;
user_menu[i].key = u->key;
i++;
}
}
if(i > 2)
return show_menu(user_menu, i);
kill_menu();
return -1;
}
int
show_user_list()
{
register int i;
register yuser *u;
static char name_buf[25], stat_buf[25];
i = 0;
user_menu[i].item = "User List";
user_menu[i].func = NULL;
user_menu[i].key = ' ';
i++;
user_menu[i].item = "Name Winsize [My_Size] Software ";
user_menu[i].func = NULL;
user_menu[i].key = ' ';
i++;
user_menu[i].item = "";
user_menu[i].func = NULL;
user_menu[i].key = ' ';
i++;
for(u = connect_list; u && i < MAXUMENU; u = u->next)
if(u != me)
{
if(u->remote.vmajor > 2)
sprintf(stat_buf, "YTalk V%d.%d",
u->remote.vmajor, u->remote.vminor);
else if(u->remote.vmajor == 2)
sprintf(stat_buf, "YTalk V2.?");
else
sprintf(stat_buf, "UNIX Talk");
pad_str(u->full_name, 15, name_buf);
pad_str(stat_buf, 15, stat_buf);
sprintf(user_buf[i], "%s %3.3dx%3.3d [%3.3dx%3.3d] %s",
name_buf,
u->remote.cols, u->remote.rows,
u->remote.my_cols, u->remote.my_rows,
stat_buf);
user_menu[i].item = user_buf[i];
user_menu[i].func = NULL;
user_menu[i].key = ' ';
i++;
}
for(u = wait_list; u && i < MAXUMENU; u = u->next)
{
pad_str(u->full_name, 15, name_buf);
pad_str("<unconnected>", 15, stat_buf);
sprintf(user_buf[i], "%s %s",
name_buf,
stat_buf);
user_menu[i].item = user_buf[i];
user_menu[i].func = NULL;
user_menu[i].key = ' ';
i++;
}
return show_menu(user_menu, i);
}
int
show_error_menu(str1, str2)
char *str1, *str2;
{
register int i;
for(i = 0; error_menu[i].key != '\0'; i++)
if(error_menu[i].item == NULL)
{
strncpy(err_str[got_error], str1, MAXERR);
err_str[got_error][MAXERR-1] = '\0';
error_menu[i++].item = err_str[got_error++];
strncpy(err_str[got_error], str2, MAXERR);
err_str[got_error][MAXERR-1] = '\0';
error_menu[i++].item = err_str[got_error++];
return show_menu(error_menu, i);
}
return 0;
}
/* Prompt user for yes/no response. Return the response. It is
* necessary for this function to hang until an answer is received.
*/
int
yes_no(prompt)
char *prompt;
{
int out = 0;
yes_no_menu[0].func = NULL;
yes_no_menu[0].key = ' ';
/* show the menu and call input_loop() */
do {
yes_no_menu[0].item = prompt;
menu_ptr = yes_no_menu;
update_menu();
input_loop();
if(menu_ptr != yes_no_menu || yes_no_menu[0].item != prompt)
{
/* somebody pre-empted us */
kill_menu();
io_len = 0;
}
for(; io_len > 0; io_len--, io_ptr++)
{
if(*io_ptr == 'y' || *io_ptr == 'Y')
{
out = 'y';
break;
}
if(*io_ptr == 'n' || *io_ptr == 'N' || *io_ptr == 27)
{
out = 'n';
break;
}
}
} while(out == 0);
kill_menu();
io_len = 0;
return out;
}
void
update_user_menu()
{
if(menu_ptr == user_menu)
{
redraw_term(me, 0);
if(user_menu[0].func) /* it's a user menu */
(void)show_user_menu(user_menu[0].item, user_menu[0].func);
else /* it's a user status list */
(void)show_user_list();
update_menu();
}
}