Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Программирование Cи / Богатырев_Язык Си в системе Unix

.pdf
Скачиваний:
80
Добавлен:
25.04.2015
Размер:
1.19 Mб
Скачать

А. Богатырёв, 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 */