DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦f55430b45⟧ TextFile

    Length: 7284 (0x1c74)
    Types: TextFile
    Notes: UNIX file
    Names: »select.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦f4b8d8c84⟧ UNIX V7 Filesystem
        └─ ⟦this⟧ »unimenu/src/menu/select.c« 

TextFile

/*
 *
 * 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 */
}