char *mytty;
extern char *getlogin (); /* */
char *userName = getlogin ();
srand (getpid () + getuid ()); /*
* */
/* */
for (nitems = 0; menuText[nitems].m_text != NULL; nitems++);
/* */
tinit (); ttinit();
mytty = ttyname(fdtty);
openVisual ();
. , 1992-95 - 365 - UNIX
again:
clearScreen ();
if (mytty != NULL && userName != NULL) {
gotoXY (0, TIMELINE);
bold ();
printf ("%s", userName);
normal ();
printf (" at %s (%s)", mytty, tname);
}
drawTitle ("", Y_TOP - 4);
drawTitle (title, Y_TOP - 3);
drawTitle ("", Y_TOP - 2);
/* */
for (i = 0; i < nitems; i++) {
drawItem (i, 20, Y_TOP + i, 0);
}
/* */
for (n=0; ; ) {
printTime (); /* */
drawItem (n, 20, Y_TOP + n, 1);
c = getcharacter ();
drawItem (n, 20, Y_TOP + n, 0);
switch (c) {
case ' ':
go_down:
n++;
if (n == nitems)
n = 0;
break;
case '\b': case 0177:
n--;
if (n < 0)
n = nitems - 1;
break;
case ESC:
goto out;
case '\t': /* Unselect item */
if (menuText[n].m_label != 0) {
menuText[n].m_label = 0;
drawItem (n, 20, Y_TOP + n, 0);
nselected--;
prSelects ();
}
goto go_down;
. , 1992-95 - 366 - UNIX
case '\r': /* Select item */
case '\n':
bold ();
drawTitle (menuText[n].m_text, LINES - 2);
/* last but two line */
normal ();
if (menuText[n].m_label == 0) {
menuText[n].m_label = 1;
drawItem (n, 20, Y_TOP + n, 0);
nselected++;
prSelects ();
}
goto go_down;
default:
goto go_down;
}
}
out:
clearScreen ();
gotoXY (COLS / 3, LINES / 2);
bold ();
printf (" .");
normal ();
/* */
while (!(c = readkey ())) {
/* */
gotoXY (rand () % (COLS - 1), rand () % LINES);
putchar ("@.*"[rand () % 3]); /* */
fflush (stdout);
}
standout ();
printf (" 0%o\n", c & 0377);
standend ();
if (c == ESC) {
sleep (2); /* 2 */
goto again;
}
die (0); /* ,
* */
}
. , 1992-95 - 367 - UNIX
/* i
* (x,y)
*/
void drawItem (i, x, y, out) {
gotoXY (x, y);
if (out) {
standout ();
bold ();
}
printf ("%c %s ",
menuText[i].m_label ? '-' : ' ', /* */
menuText[i].m_text /* */
);
if (out) {
standend ();
normal ();
}
}
/* */
void drawTitle (title, y) char *title; {
register int n;
int length = strlen (title); /* */
gotoXY (0, y);
/* clearEOL(); */
standout ();
for (n = 0; n < (COLS - length) / 2; n++)
putchar (' ');
printf ("%s", title); n += length;
/* */
for (; n < COLS - 1; n++)
putchar (' ');
standend ();
}
/* */
void prSelects () {
char buffer[30];
if (nselected == 0) {
gotoXY (0, LINES - 1);
clearEOL ();
}
else {
sprintf (buffer, ": %d/%d", nselected, nitems);
drawTitle (buffer, LINES - 1);
}
}
. , 1992-95 - 368 - UNIX
/* -------------------------- */
#define PAUSE 4
int alarmed; /* */
/* "" */
void onalarm (nsig) {
alarmed = 1;
}
/* , PAUSE .
* ''.
*/
int getcharacter () {
int c;
fflush(stdout);
/* */
signal (SIGALRM, onalarm);
alarmed = 0; /* */
/* "" PAUSE */
alarm (PAUSE);
/* .
* ,
* .
*/
c = getchar ();
/* */
if (!alarmed) { /* */
alarm (0); /* */
return c;
}
/* "" */
return ' '; /* */
}
/* ---- NDELAY read ----------------------------- */
/* 0 ,
*
*/
char readkey () {
char c;
int nread;
nread = read (fdtty, &c, 1);
/* read() .
* O_NDELAY , " 0 ".
*/
return (nread == 0) ? 0 : c;
}
. , 1992-95 - 369 - UNIX
/* -------- ------------------------ */
void printTime () {
time_t t; /* */
struct tm *tm;
extern struct tm *localtime ();
char tmbuf[30];
static char *week[7] = { "", "", "", "", "", "", "" };
static char *month[12] = { "", "", "", "", "", "",
"", "", "", "", "", "" };
time (&t); /* */
tm = localtime (&t); /* */
sprintf (tmbuf, "%2s %02d:%02d:%02d %02d-%3s-%d",
week[tm -> tm_wday], /* (0..6) */
tm -> tm_hour, /* (0..23) */
tm -> tm_min , /* (0..59) */
tm -> tm_sec , /* (0..59) */
tm -> tm_mday, /* (1..31) */
month[tm -> tm_mon], /* (0..11) */
tm -> tm_year + 1900 /* */
);
gotoXY (COLS / 2, TIMELINE);
clearEOL ();
gotoXY (COLS - strlen (tmbuf) - 1, TIMELINE);
bold ();
printf ("%s", tmbuf);
normal ();
}
8.14. , 20
. :
a) .
b) termcap,
.
c) , curses.
d) curses, 2- 2-
.
e) .
8.15. -
(ECHO).
8.16. " " (CBREAK). , -
, |-.
____________________
|- "character lists" - clist. "" (raw)
clist, , ; "" clist,
- , .
( )
( ICANON).
. , 1992-95 - 370 - UNIX
"" ""
--->--*-->-->read
| -
V /dev/tty??
|
<------<--*--<-----------<---write
-
, read-:
. , ICANON,
: -
, CTRL/U ;
|=.
(
read, gets, putchar) , <ENTER>
'\n'. ,
- "" read. '\n',
,
.
, "" :
<ENTER>. CBREAK
( '\n'). -
, . -
- !
, <ENTER> (" ") - '\n' - "-
" , , -
. - .
MS DOS ~ECHO+CBREAK getch(). UNIX
getchar(), -
tty ioctl.
( ).
( |-|-).
(, , -
write) (
);
. .
8.17. , -
. , ANSI,
:
"\033[A" Home "\033[H"
"\033[B" End "\033[F"
"\033[C" PgUp "\033[I"
"\033[D" PgDn "\033[G"
(
'\033' (escape), escape-).
0xFF. ,
, - (
).
____________________
|= , , ... -
ioctl. .
|-|- ""
, stty sane
. , 1992-95 - 371 - UNIX
, '\033'
- Esc. ,
033 -
, alarm(1);
- 033 Esc.
, . -
(0..0377), >= 0400.
,
:
termcap. -
(
. - ,
):
---> '\033' ---> '[' ---> 'A' --> 0400
| \--> 'B' --> 0401
| \--> 'C' --> 0402
| \--> 'D' --> 0403
\--> 'X' -----------> 0404
...
.
curses .
, keypad:
int c; WINDOW *window;
...
keypad(window, TRUE);
...
c = wgetch(window);
wgetch() .
<curses.h> KEY_LEFT, KEY_RIGHT
... ,
window stdscr ( -
include- curses.h).
# ======================================== Makefile getch
getch: getch.o
cc getch.o -o getch -ltermlib
getch.o: getch.c getch.h
cc -g -DUSG -c getch.c
. , 1992-95 - 372 - UNIX
/* . */
/* ================================================== getch.h */
#define FALSE 0
#define TRUE 1
#define BOOLEAN unsigned char
#define INPUT_CHANNEL 0
#define OUTPUT_CHANNEL 1
#define KEY_DOWN 0400
#define KEY_UP 0401
#define KEY_LEFT 0402
#define KEY_RIGHT 0403
#define KEY_PGDN 0404
#define KEY_PGUP 0405
#define KEY_HOME 0406
#define KEY_END 0407
#define KEY_BACKSPACE 0410
#define KEY_BACKTAB 0411
#define KEY_DC 0412
#define KEY_IC 0413
#define KEY_DL 0414
#define KEY_IL 0415
#define KEY_F(n) (0416+n)
#define ESC ' 33'
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-95 - 373 - 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 S[2]
#define key_backtab S[3]
#define key_left S[4]
#define key_right S[5]
#define key_up S[6]
#define key_down S[7]
#define key_ic S[8]
#define key_dc S[9]
#define key_il S[10]
#define key_dl S[11]
#define key_f1 S[12]
#define key_f2 S[13]
#define key_f3 S[14]
#define key_f4 S[15]
#define key_f5 S[16]
#define key_f6 S[17]
#define key_f7 S[18]
#define key_f8 S[19]
#define key_f9 S[20]
#define key_f10 S[21] /* f0 */
#define key_f11 S[22] /* f11 */
#define key_f12 S[23] /* f12 */
#define key_home S[24]
#define key_end S[25]
#define key_npage S[26]
#define key_ppage S[27]
#define TOTAL 28
. , 1992-95 - 374 - 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-95 - 375 - 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-95 - 376 - 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-95 - 377 - 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-95 - 378 - 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;
. , 1992-95 - 379 - UNIX
while (--bufp > buffer)
putback(*bufp);
return(*bufp & 0377);
}
void _sigalrm(int n)
{
alarmed = TRUE;
longjmp(jbuf, 1);
}
. , 1992-95 - 380 - UNIX
/* ==================================================================== */
#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-95 - 381 - 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, KEY_BACKSPACE);
add_to_try("\b", KEY_BACKSPACE);
add_to_try("\177", KEY_BACKSPACE);
add_to_try(key_backtab, KEY_BACKTAB);
add_to_try(key_dc, KEY_DC);
add_to_try(key_dl, KEY_DL);
add_to_try(key_down, KEY_DOWN);
add_to_try(key_f1, KEY_F(1));
add_to_try(key_f2, KEY_F(2));
add_to_try(key_f3, KEY_F(3));
add_to_try(key_f4, KEY_F(4));
add_to_try(key_f5, KEY_F(5));
add_to_try(key_f6, KEY_F(6));
add_to_try(key_f7, KEY_F(7));
add_to_try(key_f8, KEY_F(8));
add_to_try(key_f9, KEY_F(9));
add_to_try(key_f10, KEY_F(10));
add_to_try(key_f11, KEY_F(11));
add_to_try(key_f12, KEY_F(12));
add_to_try(key_home, KEY_HOME);
add_to_try(key_ic, KEY_IC);
add_to_try(key_il, KEY_IL);
add_to_try(key_left, KEY_LEFT);
add_to_try(key_npage, KEY_PGDN);
add_to_try(key_ppage, KEY_PGUP);
add_to_try(key_right, KEY_RIGHT);
add_to_try(key_up, KEY_UP);
add_to_try(key_end, KEY_END);
}
. , 1992-95 - 382 - 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;
. , 1992-95 - 383 - UNIX
ptr->ch = *(str++);
ptr->value = 0;
}
/* at this point, we are adding to the try. ptr->child == NULL */
while (*str)
{
ptr->child = (struct try *) malloc(sizeof *ptr);
ptr = ptr->child;
if (ptr == (struct try *)NULL)
{
out_of_memory = TRUE;
ptr = savedptr;
while (ptr != (struct try *)NULL)
{
savedptr = ptr->child;
free(ptr);
ptr = savedptr;
}
return;
}
ptr->child = ptr->sibling = (struct try *)NULL;
ptr->ch = *(str++);
ptr->value = 0;
}
ptr->value = code;
return;
}
/* */
void keypad_on(){
if( keypadok ) return;
keypadok = TRUE;
if( keypad_xmit ) _puts( keypad_xmit );
}
/* */
void keypad_off(){
if( !keypadok ) return;
keypadok = FALSE;
if( keypad_local ) _puts( keypad_local );
}
. , 1992-95 - 384 - UNIX
/* */
int dotest()
{
struct termios saved_modes;
int c;
char *s;
char keyname[20];
if( tcgetattr(INPUT_CHANNEL, &saved_modes) < 0 ){
err: keyboard_access_denied();
}
if( tcsetattr(INPUT_CHANNEL, TCSADRAIN, &new_modes) < 0 )
goto err;
keyreset();
for(;;){
c = getch();
switch(c){
case KEY_DOWN: s = "K_DOWN" ; break;
case KEY_UP: s = "K_UP" ; break;
case KEY_LEFT: s = "K_LEFT" ; break;
case KEY_RIGHT: s = "K_RIGHT" ; break;
case KEY_PGDN: s = "K_PGDN" ; break;
case KEY_PGUP: s = "K_PGUP" ; break;
case KEY_HOME: s = "K_HOME" ; break;
case KEY_END: s = "K_END" ; break;
case KEY_BACKSPACE: s = "K_BS" ; break;
case '\t': s = "K_TAB" ; break;
case KEY_BACKTAB: s = "K_BTAB" ; break;
case KEY_DC: s = "K_DEL" ; break;
case KEY_IC: s = "K_INS" ; break;
case KEY_DL: s = "K_DL" ; break;
case KEY_IL: s = "K_IL" ; break;
case KEY_F(1): s = "K_F1" ; break;
case KEY_F(2): s = "K_F2" ; break;
case KEY_F(3): s = "K_F3" ; break;
case KEY_F(4): s = "K_F4" ; break;
case KEY_F(5): s = "K_F5" ; break;
case KEY_F(6): s = "K_F6" ; break;
case KEY_F(7): s = "K_F7" ; break;
case KEY_F(8): s = "K_F8" ; break;
case KEY_F(9): s = "K_F9" ; break;
case KEY_F(10): s = "K_F10" ; break;
case KEY_F(11): s = "K_F11" ; break;
case KEY_F(12): s = "K_F12" ; break;
case ESC: s = "ESC" ; break;
case EOF: s = "K_EOF" ; break;
case '\r': s = "K_RETURN"; break;
case '\n': s = "K_ENTER" ; break;
default:
s = keyname;
if( c >= 0400 ){
sprintf(keyname, "K_F%d", c - KEY_F(0));
} else if( iscntrl(c)){
sprintf(keyname, "CTRL(%c)", c + 'A' - 1);
} else {
sprintf(keyname, "%c", c );
. , 1992-95 - 385 - UNIX
}
}
printf(": %s\n\r", s);
if(c == ESC)
break;
}
tcsetattr(INPUT_CHANNEL, TCSADRAIN, &saved_modes);
}
/* */
void tinit (void) {
/* static */ char Tbuf[2048];
/* Tbuf , tgetstr().
* static, keyinit()
* tinit(), .
*/
char *tname;
extern char *getenv();
if((tname = getenv("TERM")) == NULL){
printf("TERM : .\n");
exit(2);
}
printf(": %s\n", tname);
/* Tbuf */
switch (tgetent(Tbuf, tname)) {
case -1:
printf (" TERMCAP (/etc/termcap).\n");
exit (1);
case 0:
printf (" '%s' .\n", tname);
exit (2);
case 1:
break; /* OK */
}
if(strlen(Tbuf) >= 1024)
printf(" - \n");
keyinit(); /* , Tbuf[] */
}
void main(void){
setlocale(LC_ALL, "");
tinit();
/* keyinit(); */
dotest();
exit(0);
}
.
(, , .):
. , -
, -
'\0', . ?
strcmp :
. , 1992-95 - 386 - UNIX
"zzzzzzzzzza"
"zzzzzzzzzzb"
"zzzzzzzzzzbx"
"zzzzzzzzzzc"
"zzzzzzzzzzcx"
( ) zzzzzzzzzzcx
zzzzzzzzzza | 11 ,
zzzzzzzzzzb | 11 ,
zzzzzzzzzzbx | 12 ,
zzzzzzzzzzc | 11 ,
zzzzzzzzzzcx V 12 ,
: 57 . :
__z__z__z__z__z__z__z__z__z__z__a__\0
|_b__\0
| |_x__\0