Программирование Cи / Богатырев_Язык Си в системе Unix
.pdfА. Богатырёв, 1992-96 |
- 321 - |
Си в UNIX™ |
extern char *tgetstr();
void _put(char c); void _puts(char *s);
void keyboard_access_denied(void); char *strdup(const char *s);
void keyinit(void); int getc_raw(void); void keyreset(void); int getch(void); int lgetch(BOOLEAN); int ggetch(BOOLEAN); int kgetch(void);
void _sigalrm(int n); void init_keytry(void);
void add_to_try(char *str, short code); void keypad_on(void);
void keypad_off(void); int dotest(void); void tinit(void); void main(void);
А. Богатырёв, 1992-96 |
- 322 - |
Си в UNIX™ |
/* ===================================================== getch.c
*The source version of getch.c file was
*written by Pavel Curtis.
*
*/
#include <stdio.h> #include <signal.h> #include <setjmp.h> #include <termios.h> #include <ctype.h> #include <string.h> #include <locale.h> #include "getch.h"
#define |
keypad_local |
S[0] |
#define |
keypad_xmit |
S[1] |
#define key_backspace #define key_backtab
#define key_left #define key_right #define key_up #define key_down
#define key_ic #define key_dc #define key_il #define key_dl
#define key_f1 #define key_f2 #define key_f3 #define key_f4 #define key_f5 #define key_f6 #define key_f7 #define key_f8 #define key_f9 #define key_f10 #define key_f11 #define key_f12 #define key_home #define key_end #define key_npage #define key_ppage
S[2]
S[3]
S[4]
S[5]
S[6]
S[7]
S[8]
S[9]
S[10]
S[11]
S[12] |
|
S[13] |
|
S[14] |
|
S[15] |
|
S[16] |
|
S[17] |
|
S[18] |
|
S[19] |
|
S[20] |
|
S[21] |
/* f0 */ |
S[22] |
/* f11 */ |
S[23] |
/* f12 */ |
S[24] |
|
S[25] |
|
S[26] |
|
S[27] |
|
#define TOTAL 28
А. Богатырёв, 1992-96 |
- 323 - |
Си в UNIX™ |
/* descriptors for keys */ char *KEYS[TOTAL+1] = {
"ke", "ks",
"kb", "kB",
"kl", "kr", "ku", "kd", "kI", "kD", "kA", "kL",
"f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f0", "f.", "f-",
"kh", "kH", "kN", "kP",
NULL
}, *S[TOTAL];
void _put (char c) { write( INPUT_CHANNEL, &c, 1 ); } void _puts(char *s) { tputs ( s, 1, _put ); }
static int _backcnt = 0; static char _backbuf[30];
static struct try {
struct try *child; struct try *sibling; char ch;
short value; } *_keytry;
BOOLEAN keypadok = FALSE;
struct termios new_modes;
void keyboard_access_denied(){ printf( "Клавиатура недоступна.\n" ); exit(1); } char *strdup(const char *s) { return strcpy((char *) malloc(strlen(s)+1), s); }
А. Богатырёв, 1992-96 |
- 324 - |
Си в UNIX™ |
/* Инициализация таблицы строк */ void keyinit(){
char *key, nkey[80], *p; register i;
keyreset();
for( i=0; i < TOTAL; i++ ){ p = nkey;
printf("tgetstr(%s)...", KEYS[i]); key = tgetstr(KEYS[i], &p);
if(S[i]) free(S[i]); if(key == NULL){
S[i] = NULL; /* No such key */ printf("клавиша не определена.\n");
}else{
/* Decrypted string */ S[i] = strdup(key); printf("считано.\n");
}
}
init_keytry();
if( tcgetattr(INPUT_CHANNEL, &new_modes) < 0 ){ keyboard_access_denied();
}
/* input flags */
/* отменить преобразование кода '\r' в '\n' на вводе */
new_modes.c_iflag &= ~ICRNL; |
|
|
if ((new_modes.c_cflag & CSIZE) == CS8) |
/* 8-битный код */ |
|
new_modes.c_iflag &= ~ISTRIP; |
/* отменить & 0177 |
на вводе */ |
/* output flags */ |
|
|
/* отменить TAB3 - замену табуляций '\t' на пробелы */
/* отменить ONLCR - замену '\n' на пару '\r\n' на выводе */ new_modes.c_oflag &= ~(TAB3 | ONLCR);
/* local flags */
/* выключить режим ICANON, включить CBREAK */
/* выключить эхоотображение набираемых символов */ new_modes.c_lflag &= ~(ICANON | ECHO);
/* control chars */ |
/* |
при вводе с клавиш ждать не более ... */ |
|||
new_modes.c_cc[VMIN] |
= 1; |
/* |
1 |
символа и */ |
|
new_modes.c_cc[VTIME] = 0; |
/* |
0 |
секунд |
*/ |
|
/* Это соответствует режиму |
CBREAK */ |
|
/* Символы, нажатие которых заставляет драйвер терминала послать сигнал
*либо отредактировать набранную строку. Значение 0 означает,
*что соответствующего символа не будет */
new_modes.c_cc[VINTR] |
= '\0'; /* символ, генерящий SIGINT |
*/ |
||
new_modes.c_cc[VQUIT] |
= '\0'; /* символ, генерящий SIGQUIT */ |
|||
new_modes.c_cc[VERASE] |
= '\0'; |
/* забой (отмена |
последнего символа)*/ |
|
new_modes.c_cc[VKILL] |
= '\0'; |
/* символ отмены |
строки |
*/ |
}
А. Богатырёв, 1992-96 |
- 325 - |
Си в UNIX™ |
/* Чтение одного символа непосредственно с клавиатуры */ int getc_raw(){
int n; char c;
n = read(INPUT_CHANNEL, &c, 1); if (n <= 0) return EOF; return (c & 0xFF);
}
static |
BOOLEAN |
_getback |
= |
FALSE; |
static |
char |
_backchar |
= |
'\0'; |
/* Чтение символа - либо из буфера (если не пуст), либо с |
клавиатуры |
*/ |
|||
#define nextc() |
(_backcnt > 0 |
? |
_backbuf[--_backcnt] |
: \ |
|
|
_getback |
? |
_getback = FALSE, |
_backchar |
: \ |
|
|
|
getc_raw()) |
|
|
#define putback(ch) |
_backbuf[_backcnt++] = ch |
|
|
void keyreset(){
_backcnt = 0; _backchar = '\0'; _getback = FALSE;
}
/* Функция чтения составного символа */ int getch(){
int c = lgetch(TRUE); keypad_off();
return c;
}
/*
ВНИМАНИЕ!
Если в процессе будет получен сигнал,
в то время как процесс находится внутри вызова getch(), то системный вызов read() вернет 0 и errno == EINTR.
В этом случае getch() вернет '\0'.
Чтобы избежать этой ситуации используется функция lgetch()
*/
int lgetch(BOOLEAN kpad) { int c;
while((c = ggetch(kpad)) <= 0); return c;
}
int ggetch(BOOLEAN kpad) { int kgetch();
if( kpad ) keypad_on(); else keypad_off();
return keypadok ? kgetch() : nextc();
}
А. Богатырёв, 1992-96 |
- 326 - |
Си в UNIX™ |
/*
**int kgetch()
**Get an input character, but take care of keypad sequences, returning
**an appropriate code when one matches the input. After each character
**is received, set a one-second alarm call. If no more of the sequence
**is received by the time the alarm goes off, pass through the sequence
**gotten so far.
**
*/
#define CRNL(c) (((c) == '\r') ? '\n' : (c))
/* борьба с русской клавиатурой */ #if !defined(XENIX) || defined(VENIX)
#define unify(c) ( (c)&(( (c)&0100 ) ? ~0240 : 0377 )) #else
#define unify(c) (c)
#endif
А. Богатырёв, 1992-96 |
- 327 - |
Си в UNIX™ |
/* ==================================================================== */ #if !defined(XENIX) && !defined(USG) && !defined(M_UNIX) && !defined(unix)
/* Для семейства BSD */
static BOOLEAN |
alarmed; |
|
|
jmp_buf |
jbuf; |
|
|
int kgetch() |
|
|
|
{ |
|
|
|
register struct try |
*ptr; |
|
|
int |
ch; |
|
|
char |
buffer[10]; |
/* Assume no sequences longer than 10 */ |
|
register char |
*bufp = buffer; |
||
void |
(*oldsig)(); |
|
|
void |
_sigalrm(); |
|
ptr = _keytry;
oldsig = signal(SIGALRM, _sigalrm); alarmed = FALSE;
if( setjmp( jbuf )) /* чтоб свалиться сюда с read-а */ ch = EOF;
do
{
if( alarmed ) |
|
break; |
|
ch = nextc(); |
|
if (ch != EOF) |
/* getc() returns EOF on error, too */ |
*(bufp++) = ch; |
|
if (alarmed) |
|
break; |
|
while (ptr != (struct try *)NULL &&
(ch == EOF || unify(CRNL(ptr->ch)) != unify(CRNL(ch)) )) ptr = ptr->sibling;
if (ptr != (struct try *)NULL)
{
if (ptr->value != 0)
{
alarm(0); signal(SIGALRM, oldsig); return(ptr->value);
}
else
{
ptr = ptr->child; alarm(1);
}
}
} while (ptr != (struct try *)NULL);
alarm(0); signal(SIGALRM, oldsig);
if (ch == EOF && bufp == buffer) return ch;
while (--bufp > buffer) putback(*bufp);
return(*bufp & 0377);
}
А. Богатырёв, 1992-96 |
- 328 - |
Си в UNIX™ |
void _sigalrm(int n)
{
alarmed = TRUE; longjmp(jbuf, 1);
}
/* ==================================================================== */ #else /* XENIX or USG */
/* Для семейства SYSTEM V */
static BOOLEAN alarmed; |
|
|
|
int kgetch() |
|
|
|
{ |
|
|
|
register struct try |
*ptr; |
|
|
int |
ch; |
|
|
char |
buffer[10]; |
/* Assume no sequences longer than 10 */ |
|
register char |
*bufp = buffer; |
||
void |
(*oldsig)(); |
|
|
void |
_sigalrm(); |
|
ptr = _keytry;
oldsig = signal(SIGALRM, _sigalrm); alarmed = FALSE;
do
{
ch = nextc(); |
|
if (ch != EOF) |
/* getc() returns EOF on error, too */ |
*(bufp++) = ch; |
|
if (alarmed) |
|
break; |
|
while (ptr != (struct try *)NULL &&
(ch == EOF || unify(CRNL(ptr->ch)) != unify(CRNL(ch)) )) ptr = ptr->sibling;
if (ptr != (struct try *)NULL)
{
if (ptr->value != 0)
{
alarm(0); signal(SIGALRM, oldsig); return(ptr->value);
}
else
{
ptr = ptr->child; alarm(1);
}
}
} while (ptr != (struct try *)NULL);
alarm(0); signal(SIGALRM, oldsig);
if (ch == EOF && bufp == buffer) return ch;
while (--bufp > buffer) putback(*bufp);
return(*bufp & 0377);
}
А. Богатырёв, 1992-96 |
- 329 - |
Си в UNIX™ |
void _sigalrm(int n)
{
alarmed = TRUE; signal(SIGALRM, _sigalrm);
}
#endif /*XENIX*/
/* ==================================================================== */ /*
**init_keytry()
**Построение дерева разбора последовательностей символов.
*/
void init_keytry()
{
_keytry = (struct try *) NULL;
add_to_try(key_backspace, add_to_try("\b", add_to_try("\177",
add_to_try(key_backtab, add_to_try(key_dc, add_to_try(key_dl, add_to_try(key_down,
add_to_try(key_f1, add_to_try(key_f2, add_to_try(key_f3, add_to_try(key_f4, add_to_try(key_f5, add_to_try(key_f6, add_to_try(key_f7, add_to_try(key_f8, add_to_try(key_f9, add_to_try(key_f10, add_to_try(key_f11, add_to_try(key_f12, add_to_try(key_home, add_to_try(key_ic, add_to_try(key_il, add_to_try(key_left, add_to_try(key_npage, add_to_try(key_ppage, add_to_try(key_right, add_to_try(key_up, add_to_try(key_end,
KEY_BACKSPACE); KEY_BACKSPACE); KEY_BACKSPACE);
KEY_BACKTAB); KEY_DC); KEY_DL); KEY_DOWN);
KEY_F(1));
KEY_F(2));
KEY_F(3));
KEY_F(4));
KEY_F(5));
KEY_F(6));
KEY_F(7));
KEY_F(8));
KEY_F(9));
KEY_F(10));
KEY_F(11));
KEY_F(12));
KEY_HOME);
KEY_IC);
KEY_IL);
KEY_LEFT);
KEY_PGDN);
KEY_PGUP);
KEY_RIGHT);
KEY_UP);
KEY_END);
}
А. Богатырёв, 1992-96 |
- 330 - |
Си в UNIX™ |
void add_to_try(char *str, short code)
{
static |
BOOLEAN |
out_of_memory = FALSE; |
struct |
try |
*ptr, *savedptr; |
if (str == NULL || out_of_memory) return;
if (_keytry != (struct try *) NULL)
{
ptr = _keytry;
for (;;)
{
while (ptr->ch != *str && ptr->sibling != (struct try *)NULL) ptr = ptr->sibling;
if (ptr->ch == *str)
{
if (*(++str))
{
if (ptr->child != (struct try *)NULL) ptr = ptr->child;
else break;
}
else
{
ptr->value = code; return;
}
}
else
{
if ((ptr->sibling =
(struct try *) malloc(sizeof *ptr)) == (struct try *)NULL)
{
out_of_memory = TRUE; return;
}
savedptr = ptr = ptr->sibling;
ptr->child = ptr->sibling = (struct try *)NULL; ptr->ch = *str++;
ptr->value = 0;
break;
}
} /* end for (;;) */
}
else /* _keytry == NULL :: First sequence to be added */
{
savedptr = ptr = _keytry = (struct try *) malloc(sizeof *ptr);
if (ptr == (struct try *) NULL)
{
out_of_memory = TRUE; return;
}
ptr->child = ptr->sibling = (struct try *) NULL; ptr->ch = *(str++);
ptr->value = 0;
}
/* at this point, we are adding to the try. ptr->child == NULL */