|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 7284 (0x1c74)
Types: TextFile
Notes: UNIX file
Names: »select.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »unimenu/src/menu/select.c«
/*
*
* select this is the input function. It puts up the formatted
* menu block then reads from the keyboard. Input may be
* arrow keys for moving the reverse video block or chars
* to select a specific entry. Esc cancels this menu,
* "?" returns a help request for the current choice,
* return causes the exec of the current choice.
* When alpha chars are entered, the list of prompts
* is searched for a match in the first character. We then
* make that choice the current choice
*
* passed: menu pointer, pointer to place to put the choice type
*
* returns: the choice number we were on or -1 to quit. and the
* choice type through "*chtype".
*
* history original code Mar 85 Dan Mitchell
*/
/*
#define DEBUG
*/
#include "defs.h"
#include <sys/stat.h>
#define ESCK 27
#define CR 13
#define HELP '?'
#define HOME 199
#define UPK 200
#define PGUP 201
#define LFT 203
#define RGT 205
#define END 207
#define DN 208
#define PGDN 209
#ifdef XENIX
#define WINDEV 20 /* major device number for a window */
#endif
#ifdef COHERENT
#define WINDEV 10
#endif
#define MAXLINE 40
extern int *Scrnbuf;
extern int Top;
int Runwin = -1;
int Rloc = 0; /* left hand row of the menu */
int Cloc = 0; /* left hand col of the menu */
/*
these can be used to size the window
int Winrows = 0;
int Wincols = 0;
*/
int select(menu, chtype)
struct menu_f *menu;
int *chtype;
{
int chnum; /* the choice number */
int row; /* current row in the menu */
int col; /* current column in the menu */
int gotcmd; /* signals we are through */
int width; /* width of the choice fields */
int y, x; /* keep track of swap location */
UINT8 key; /* for input */
#ifdef DEBUG
char dbg[5];
printf("In select");
read(0, dbg, 1);
#endif
if ( menu->m_entries <= 0 ) /* what???! */
{
write(2, "select: no entries!\n", 20);
_exit(1);
}
/*
* check the window every time in case we're running
* a sub menu in a new window. also makes sure we're on
* a window
*/
if ( setwin() < 0 )
{
printf("Must run in a window\n");
_exit(1);
}
y = Rloc = menu->m_ulhr + 1;
x = Cloc = menu->m_ulhc + 1;
width = menu->m_fsiz;
chnum = 0;
row = 0;
col = 0;
gotcmd = 0;
#ifdef DEBUG
printf("select: window write: %D\n", (long) Scrnbuf);
read(0, dbg, 1);
#endif
if ( wr_blck(Scrnbuf, 0, 0, SCR_LEN, SCR_WID) )
_exit(1);
swap_attr(y, x, 1, width - 2);
explain(menu, 0);
to_raw();
do /* until we get the command */
{
read(0, &key, 1);
if ( key >= ' ' && key < '~' && key != '?' )
{
int i;
if ( (i = s_match(chnum, key, menu)) == -1 )
{
write(1, "\007", 1);
continue;
}
else
{
chnum = i;
col = chnum % menu->m_col;
row = chnum / menu->m_col;
}
}
else switch ( key )
{
case UPK : --row; break;
case DN : ++row; break;
case LFT : --col; break;
case RGT : ++col; break;
case END : col = menu->m_col - 1;
row = menu->m_row - 1;
break;
case HOME : col = row = 0;
break;
case PGUP :
case PGDN :
/* wsize(key); */
continue;
/* these cause us to go back */
case CR :
*chtype = CHEXEC;
gotcmd++;
continue; /* skip calculation of chnum */
case HELP :
*chtype = CHHELP;
gotcmd++;
continue;
case ESCK :
*chtype = CHEXIT;
chnum = 0;
gotcmd++;
continue;
#ifdef BIGDEBUG
/* Note: lsm() is in another module that must also have
DEBUG turned on */
case '\004' : lsm(menu);
wr_blk(Scrnbuf, 0, 0, SCR_LEN, SRC_WID);
continue;
#endif
default : write(1, "\007", 1);
continue;
}
swap_attr(y, x, 1, width - 2);
if ( row >= menu->m_row )
row = 0;
else if ( row < 0 )
row = menu->m_row - 1;
if ( col >= menu->m_col )
col = 0;
else if ( col < 0 )
col = menu->m_col - 1;
chnum = (row * menu->m_col) + col;
/*
* this kluge takes care of non-symetrical menus
* if we we're going down we set row to 0
* if we we're going up we set row to the last
* if we we're going left we set col to the last
* if we we're going right we set col to 0
* if one loop through doesn't fix it, we go home
*/
while (chnum >= menu->m_entries )
{
write(1, "\007", 1);
switch ( key )
{
case UPK : row = menu->m_row - 1; break;
case DN : row = 0; break;
case LFT : col = menu->m_col - 1; break;
case RGT : col = 0; break;
default : /* been through twice already */
chnum = col = row = 0;
continue;
}
key = 0;
chnum = (row * menu->m_col) + col;
}
y = Rloc + row;
x = Cloc + (col * width);
swap_attr(y, x, 1, width - 2);
explain(menu, chnum);
} while ( !gotcmd );
to_cooked();
return ( chnum + 1 );
}
/*
* s_match tries to match key to the first letter of
* a choice. First we search forward to the end of the list.
* If no match is found, then search from the beginning
*
* returns the number of the choice if a match was found,
* otherwise (-1)
*/
s_match(chnum, key, menu)
int chnum;
UINT8 key;
struct menu_f *menu;
{
int cnt;
struct choice_f *chp;
/*
* first search from the current choice + 1
*/
chp = menu->m_list;
for (cnt = 0; cnt <= chnum && chp; cnt++, chp = chp->c_next )
;
while ( chp )
{
if ( (*(chp->c_Text) | ' ') == (key | ' ') )
break;
chp = chp->c_next;
cnt++;
}
if ( chp ) /* a match was found */
return ( cnt );
/*
* search from the beginning to the current choice
*/
chp = menu->m_list;
for ( cnt = 0; cnt < chnum && chp; cnt++ )
{
if ( (*(chp->c_Text) | ' ') == (key | ' ') )
break;
chp = chp->c_next;
}
if ( cnt < chnum ) /* a match was found */
return ( cnt );
return ( -1 ); /* no match */
}
/*
* write to the window buffer at row. Note that
* this does not appear on the screen until another WR_BLOCK is done
*/
status(row, msg)
int row;
char *msg;
{
fillw(Scrnbuf + (SCR_WID * row), SCR_WID, SPACE);
bputstr(Scrnbuf, SCR_SIZ.word, row, 1, msg);
}
/*
* setwin determines the window we're on.
* do an fstat on stdout and look at the
* major and minor device numbers.
*/
setwin()
{
struct stat stbuf;
if ( fstat(1, &stbuf) ) /* stdout tells us window */
Runwin = -1;
else
{
if ( (stbuf.st_rdev >> 8) != WINDEV )
Runwin = -1;
else
/* minor dev number = window */
Runwin = stbuf.st_rdev & 0xff;
}
return ( Runwin );
}
/*
* explain puts a one-line explanation below the last line of the menu
*/
explain(menu, chnum)
struct menu_f *menu;
int chnum;
{
struct choice_f *chp;
int cnt;
int width;
UINT8 *s;
W2B *d;
W2B buf[80];
width = (menu->m_col * menu->m_fsiz) - (Rloc + 1);
if ( width > 80 )
width = 80;
else if ( width < 1 )
return; /* not enough room */
/* clear the prompt buffer */
for ( d = buf, cnt = 0; cnt < width; cnt++, d++ )
{
d->bytes.low = ' ';
d->bytes.high = 0x70;
}
chp = menu->m_list; /* point to list of choices */
for ( cnt = 0; cnt != chnum && chp; cnt++ )
chp = chp->c_next; /* scan for the correct entry */
if ( chp && chp->c_expl) /* if there's an expl line */
{
d = buf;
s = chp->c_expl->l_val;
while ( *s ) /* copy it over */
{
d->bytes.low = *s++;
d++;
}
/* write it to the screen */
wr_blck(buf, (Rloc + menu->m_row), Cloc + 1, 1, width);
}
pcurs(24, 80); /* "hide" the cursor */
}