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