'Programming/Etc(펌&자료)'에 해당되는 글 61건
- 2009/08/04 [C] [#ifdef~#endif] [#ifndef~#endif]
- 2009/07/26 [C] 포인터를 쓰는 이유
- 2009/07/26 [C] C언어에서 특정폴더의 파일을 모두 읽어서, 리스트를 만드는 함수가 따로 있나요?
- 2009/07/26 [C] 쉬프트연산을 통한 압축문제
- 2009/07/26 [C++] enum 의 적절한 활용 (2)
- 2009/07/26 [C] C언어 char 형 배열이 한글(unicode)을 어떻게 인식할까?
- 2009/07/20 [Linux] signal 다루기 3 (1)
- 2009/07/19 [Linux] signal 기초 -1
- 2009/07/15 [Linux] NCURSES Programming HOWTO
- 2009/07/15 [Linux] Charater Cell Graphics
- 2009/07/15 [Linux] 공유메모리 연산 관련 소스
- 2009/07/15 [Linux] shmget - 공유메모리 영역을 할당
- 2009/07/15 [Linux] shmat - 공유메모리 관리 연산
- 2009/07/15 [Linux] NCURSES 프로그래밍
- 2009/07/15 [Linux] NCURSES란 ?
- 2009/07/15 [Linux] Serial-Programming
- 2009/07/15 [Linux] linux에서 getch() 및 kbhit() 사용하기 (2)
- 2009/07/15 [C] 0xE0 == 224 ?
- 2009/07/15 [Linux] 리눅스에서 getch() 사용
- 2009/07/13 [C] WinApi 추천 사이트
- 2009/07/13 [C] 2차원 배열과 포인터
- 2009/07/12 [TCP/IP] signal set 관련 함수 (sigemptyset, sigaddset, sigdelset, sigprocmask)
- 2009/07/12 [TCP/IP] signal(SIG_CHLD, SIG_IGN)
- 2009/07/12 [TCP/IP] SIGPIPE
- 2009/07/05 [TCP/IP] 열혈강의 TCP/IP 예제 소스 (1장~10장)
만약 이 강좌가 이해가 잘 안된다면
http://kin.naver.com/detail/detail.php?d1id=1&dir_id=10104&eid=pwktyoG0krHezT0E2H9jx8zQxNWLOxXT#BtnCLose
오랜만에 C++ 상속에 대해 고민좀 하다가 조건부 컴파일이란 걸 보고 쓰게 됨.
#define, #ifdef, #ifndef, #endif 등 이것들을 '전처리기' 라고 합니다.
a. #define은 '매크로' 라고도 하며 값을 정의(치환)하는 역할을 합니다.
b. #ifdef는 'if define' = '만약 정의되어 있다면' 이란 뜻입니다.
c. #ifndef는 'if not define' = '만약 정의되어 있지 않다면' 이란 뜻입니다.
d. #endif는 꼭 b, c 끝에 써줘야 합니다.
전처리기 순서로 해석을 해보겠습니다.
#define STAR
'STAR' 라는 이름을 정의.
#ifdef STAR
printf("Star ");
#endif
만약 'STAR' 라는 이름이 정의되어 있다면, "Star " 문자열을 출력하는 printf 함수 실행
#ifndef CRAFT
printf("Craft ");
#endif
만약 'CTRAFT' 라는 이름이 정의되어 있지 않다면, 아래 명령 실행
#ifndef WAR
printf("\n");
#endif
만약 'WAR' 라는 이름이 정의되어 있지 않다면, 아래 명령 실행
주석처리된 두 코드를 주석 없애도 됩니다.
#ifndef STAR
#define STAR
#endif
만약 'STAR' 라는 이름이 정의되어 있지 않다면 'STAR'를 정의함.
저 두 코드를 주석처리하나 주석 안하나 결과는 똑같습니다.
※ 왜 저것들을 main 함수 안에 써넣었나 궁금하면 한번 밖으로 빼보세요.
[출처] [#ifdef~#endif] [#ifndef~#endif]|작성자 루트
포인터....^^*
포인터는 C의 꽃이라고 할 수 있죠..
포인터를 못하면 C, C++에 아무런 의미가 없다고 해도 과언이 아니라 생각합니다.
일반적으로 int는 4바이트 double는 8바이트.... char은 1바이트.. 이렇게 됩니다.
이러한 변수들은 그 변수에 맞는 타입을 지정할 경우에 그렇게 크기가 정해지는 것이고요..
포인터 변수.. 즉! int*, char*, double*, long*등.. 포인터가 붙은 변수들은 모두가 다 4바이트가 됩니다.
이는 0x0000부터 0xffff까지의 메모리상의 주소값이 저장될 수 있는 변수이기 때문이죠..
예를 들어 int a = 5; 라고 선언을 하게 된다면 어디엔가 4바이트의 메모리가 잡히게 되고 그 곳의 이름은 a, 그리고 그 곳의 값은 5가 되는 것이겠죠..
그렇다면 이렇게 잡히게 된 메모리에도 주소가 있지 않을까요?
네.. 그렇겠죠? 물론 모든 메모리에는 메모리의 주소가 있습니다.
그리고 이렇게 메모리 주소를 저장할 수 있는 곳의 메모리가 4바이트가 되겠고요.. 그곳 메모리의 주소는 4바이트의 메모리가 시작하는 곳의 주소를 말합니다.
여기서... 포인터 변수라 함은 이러한 주소를 저장할 수 있는 변수라 생각하시면 됩니다.
위의 a라는 변수가 잡혀있는 메모리의 주소가 0x2486이라면
int *pa;
pa = &a;
(&를 변수앞에 붙이면 해당 변수의 주소값이 되는것은 아시죠?)
이렇게 된다면 pa의 값을 printf로 찍어보면 0x2486이 되는 것이죠..
이렇게 포인터 변수는 어떤 메모리의 주소값을 가지고 있다고 생각하시면 됩니다.
char가 1바이트밖에 안되지만
char ch = 'a';
char *pch;
pch = *ca;
이런 식으로 pch에 저장을 하게 되어도 ca의 크기인 1바이트가 아닌 ca의 주소값은 4바이트이기때문에 pch의 크기는 1바이트가 아닌 4바이트가 되는 것이죠..
이와 반대로 변수의 크기가 큰 경우에도 그의 주소값은 언제나 4바이트가 되는 것이고요~^^*
이해가 잘 되셨는지 모르겠네요.. 아무튼 위의 내용은 주소값은 언제나 4바이트라는 것입니다.
그렇다면 구조체를 한 번 생각해 보지요..
만약 int, double, char, char[10]...이렇게 변수가 들어있는 구조체를 선언하게 된다면 크기가 무척 크겠죠? 이보다 더 커질 수도 있겠고요..
하지만 이러한 구조체타입의 변수를 선언해도 이 구조체 변수의 주소는 4바이트가 됩니다.
무척 긴 메모리의 주소값을 다 쓰는 것이 아니고 이 구조체가 들어가 있는 메모리의 시작점이 이 구조체 변수의 주소가 되는 것이니까요~
자 이제.. 함수가 하나 있습니다.
이 함수는 위에서 선언해 놓은 구조체 타입을 입력 매개변수로 받습니다.
만약 구조체 타입의 변수를 그냥 넘기게 된다면 상당히 큰 메모리가 하나 더 잡히게 됩니다.
넘겨받는 함수쪽에서도 같은 구조체 타입을 선언해 메모리에 잡아놓고 매개변수로 받아서 사용을 하기때문에 그만큼 메모리를 허비하게 되는 것이죠..
그런데 만약 이 구조체 전부를 넘기지 않고 이 구조체의 주소만 넘겨서 사용을 하면 받는쪽에서 4바이트의 포인터변수만 선언해서 사용을 할 수 있습니다.
그렇다면 4바이트의 메모리만 더 사용하면 된다는 얘기죠~^^*
이렇게 사용하면 메모리의 낭비가 많이 줄겠죠?
여기까지는 포인터에 관한 간략한 설명이었고요..
포인터를 사용하면 유용한 방법... 그리고 어떤 때 사용을 하는가..
이것은 여기 지식in에 질문이 많이 올라와 있을꺼엥요..
다른 것 다 필요없고요..
swap()함수에 관해 찾아보세요..
스왑함수에 관해 찾아보시면 포인터변수를 사용해 스왑하는 예제와
그냥 일반 변수를 사용해 스왑하는 예제가 있을 것이고
이를 비교하는 내용과 왜 이렇게 되는지 정말 무쟈게 많이 나와있을 것입니다.
그래서 구지 제가 쓰지는 않겠습니다.
한 번 더 찾아보는 것도 좋겠죠~^^*
저보다 더 설명 잘 해 놓았을테니까요..
스왑을 보신다면 위엣분이 써 놓으신 콜 바이 벨류와 콜 바이 어드레스에 관해 알게되실 것입니다.
프로그램을 조금 더 배우시다 보면 콜 바이 레퍼런스에 관해서도 알게되실 것이고~^^*
콜바이 레퍼런스는 콜바이 어드래스와 비슷하지만 C에서는 어드래스로 사용을 할 것이고.. 더 상위 프로그램에서는 레퍼런스로 사용합니다.
시간이 되신다면 이 내용도 한 번 찾아서 공부해 보세요.
그렇다면 포인터에 좀 더 가깝게 접근을 하시게 될 것입니다.
C언어에서 특정폴더의 파일을 모두 읽어서, 리스트를 만드는 함수가 따로 있나요?
ANSI C에는 그러한 함수에 대한 표준이 없는 걸로 알고 있습니다.
하지만... 각 C컴파일러 마다 그러한 함수를 가지고 있지요.
Visual C에서는 _findfirst()와 _findnext() 그리고 _findclose() 를 찾아 보시구요.
Unix/Linux에서는 opendir()와 readdir() 그리고 closedir()을 찾아 보십시오.
다음은 Visual C에서 Sample로 나오는 FileFind라는 소스입니다.
Example
/* FFIND.C: This program uses the 32-bit _find functions to print
* a list of all files (and their attributes) with a .C extension
* in the current directory.
*/
#include
#include
#include
void main( void )
{
struct _finddata_t c_file;
long hFile;
/* Find first .c file in current directory */
if( (hFile = _findfirst( "*.c", &c_file )) == -1L )
printf( "No *.c files in current directory!\n" );
else
{
printf( "Listing of .c files\n\n" );
printf( "\nRDO HID SYS ARC FILE DATE %25c SIZE\n", ' ' );
printf( "--- --- --- --- ---- ---- %25c ----\n", ' ' );
printf( ( c_file.attrib & _A_RDONLY ) ? " Y " : " N " );
printf( ( c_file.attrib & _A_SYSTEM ) ? " Y " : " N " );
printf( ( c_file.attrib & _A_HIDDEN ) ? " Y " : " N " );
printf( ( c_file.attrib & _A_ARCH ) ? " Y " : " N " );
printf( " %-12s %.24s %9ld\n",
c_file.name, ctime( &( c_file.time_write ) ), c_file.size );
/* Find the rest of the .c files */
while( _findnext( hFile, &c_file ) == 0 )
{
printf( ( c_file.attrib & _A_RDONLY ) ? " Y " : " N " );
printf( ( c_file.attrib & _A_SYSTEM ) ? " Y " : " N " );
printf( ( c_file.attrib & _A_HIDDEN ) ? " Y " : " N " );
printf( ( c_file.attrib & _A_ARCH ) ? " Y " : " N " );
printf( " %-12s %.24s %9ld\n",
c_file.name, ctime( &( c_file.time_write ) ), c_file.size );
}
_findclose( hFile );
}
}
Output
Listing of .c files
RDO HID SYS ARC FILE DATE SIZE
--- --- --- --- ---- ---- ----
N N N Y CWAIT.C Tue Jun 01 04:07:26 1993 1611
N N N Y SPRINTF.C Thu May 27 04:59:18 1993 617
N N N Y CABS.C Thu May 27 04:58:46 1993 359
N N N Y BEGTHRD.C Tue Jun 01 04:00:48 1993 3726
다음 int형 자료의 압축된 자료로 부터 char형으로 추출하여 출력하고자 한다.
1번과 3번에는 문장을 넣고 2번과 4번에는 결과값을 쓰시오
unsigned int p = 25300;
char a, b;
a = ________________; ---> 1번 답: p >> 8
printf("%d\n", a); ---> 2번 답: 98
b = ________________; ---> 3번 답: (char)(p)
printf("%d\n", b); ---> 4번 답: -44
---------------------------------------------------------------------------
먼저 진수의 개념과 변환에 대해 잘 아신다는 전제 하에 답변을 쓰도록 하겠습니다.
그렇지 않다면 10진수와 2진수, 16진수 등에 대해 좀 찾아보시고 답변을 읽어보세요.
십진수 25300을 16진수로 바꾸면 0x62D4 입니다.
질문에 써 주신 코드는 이 숫자 0x62D4를 0x62(98)과 0xD4(-44)로 나누려는 코드입니다.
이 값을 32비트 변수인 unsigned int형 변수 p에 넣으므로
p의 값은 0x000062D4 가 됩니다.
그럼 여기서 62를 뽑아내려면 p를 오른쪽으로 8비트만큼 쉬프트 해야겠지요.
따라서 1번 행의 답은 p >> 8 이 됩니다.
그 값을 char형 변수 a에 집어 넣으므로 a의 값은 0x62가 되는 것이고요.
따라서 2번의 출력 결과는 98 (0x62의 십진수 표현)이 됩니다.
세 번째 줄에서는 최하위 8비트만 추출해 내면 우리가 원하는 값을 얻어낼 수 있습니다.
따라서 char형으로 형 변환하여 하위 8비트만 b 변수로 대입하게 되는 것입니다.
그러면 b에는 최하위 8비트의 값인 -44 (0xD4의 십진수 표현. 이 때 최상위 비트는 1이므로 음수입니다.)
가 네 번째 줄의 실행 결과가 되겠지요.
---------------------------------------------------------------------------
< char 타입의 변수의 유효범위에 대하여 >
unsigned int 타입의 변수 p는 4 바이트(32비트) 크기의 부호없는 변수입니다...
그리고, char 타입의 변수 b 는 1 바이트(8비트) 크기의 부호있는 변수입니다...
변수는 어떠한 값을 담을 수 있는 그릇을 의미한다고 치면, 이 그릇에도 역시, 용량이 있을 것입니다...
이 char 타입의 변수에 담을 수 있는 유효범위는 -128 ~ 127 입니다...(중요 !!)
그럼... p 변수의 값을 b 변수에 대입하려 한다면...큰 그릇의 값을 작은 그릇의 값으로 옮기는 것이죠 ??
(4바이트 -> 1바이트)
그럼,,,어떻게 될까요 ?? 당연히 작은 그릇인 b 변수의 크기만큼만 담게 되고(하위 8비트) 나머지
상위 8비트는 잘려 나가게 됩니다...
10진수 25300 을 2진수로 표현하면...
0110 0010 1101 0100 이라고 했습니다...
그럼,,,여기서, 하위 8비트만 남게 됩니다...
1101 0100
=> 10진수로 이 값을 바꾸면 212 라는 값이 도출됩니다...
1101 0100 (2) == 212 (10)
char 타입의 유효범위는 -128 ~ 127 이라고 했는데, 위 값 212 는 이 b 변수의 유효범위를 벗어나게
됩니다...
원래, 변수의 유효범위를 벗어나면. 오류로 처리가 되어야 하지만. C/C++ 에서는 이 유효범위를
벗어난 값 들을 다르게 표현합니다...
즉,,,자료형의 범위보다 더 큰 값이 입력되면 초과된 값 만큼 음수쪽(작은 쪽의 값) 으로 이동된 값이~
자료형의 범위보다 더 작은 값이 입력되면 초과된 값 만큼 양수쪽(큰 쪽의 값) 으로 이동된 값이
기억 되게 됩니다...
예)
-128 ~ 127 범위를 갖는 char 타입의 변수에 128 을 대입하려고 한다면 ??
=> -128 로 표현
129 을 대입하려고 한다면 ?
=> -127 로 표현
-129 를 대입하려고 한다면 ?
=> 127 로 표현
-130 을 대입하려고 한다면 ?
=> 126 으로 표현
그러므로,,,이러한 규칙에 의하여 212 라는 값은 b 변수의 최대 값인 127 을 벗어나므로,
음수쪽으로 표현된 값인 -44 로 표현되는 것이죠...
프로그램 짜는 사람이면 누구나 enum 을 알것이다.
열거형라고 하나?? 아마 잘안쓰는 타입임에 분명할 것이다.
나는 고수들의 소스에서 enum이 어떻게 이용되는지 보고나서 충격을 금치 못했다.
극에 달한 활용이란...
enum 으로 리턴 타입을 정해주고 바로 리턴 시켜주는 기법인것이다.
예제를 보면... 이해가 쉬울것이다.
#include <stdio.h>
enum TEST_ARGUMENT{RET1=-1, RET2, RET3, RET4};
TEST_ARGUMENT testFunc(void){
TEST_ARGUMENT ret;
ret=RET1;
return ret;
}
int main(){
testFunc();
return 0;
}
소름 끼치지 않는가? 고수들의 스킬이란... 대단하다 정말,
위의 방법의 소스를 짠 사람은 러시아 사람이다. 같은 회사에 근무하는 ㅋ
리눅스 프로그래머라 그런지 윈도 위주로 공부하는 우리와는 차이가 나는 기법들이 많다.
틈틈히 그들의 소스를 보면 정말 잘 짜여졌다는 생각이 ;;
namespace /템플릿 / 클레스화는 거의 상상을 초월하는 수준인듯 ;;
배울게 너무나 많다 -0-;;
[출처] enum 의 적절한 활용.|작성자 낙엽
C언어 char 형 배열이 한글(unicode)을 어떻게 인식할까?
char[2] 에 들어간다고 봐야한다.
각설하고 unicode가 16비트이니 8비트 8비트씩 해서 0번과 1번 인덱스에 들어간다고 하자.
그리고 실제로 ㄱ부터 ㅎ까지 int값을 찍어보면 다음과 같은 결과를 얻을 수 있다.
마이너스 값이다. 아마도 첫 비트가 1인가보다.
문자를 인식하는 경우에 1번째 비트가 0이면 ASCII로 인식하고 1이면 UNICODE로 인식한다고 한다.
ㄱ->ㅎ으로 갈수록 1씩 증가한다.
ㅏ->ㅣ으로 갈수록 1씩 증가한다.
시그널의 특징 : 시그널은 대기열이 없다
시그널은 한 프로세스에 대해서 발생하는 시그널을 큐잉 하지 못한다(대부분의 유닉스). 특정 프로세스에 보내는 시그널은 커널에서 관리하는데 이때 커널은 프로세스에게 보낼 시그널을 한개 이상 유지할수 없다.시그널을 받게 되면, 프로세스는 시그널 핸들러(신호 처리기)를 이용해서 시그널에 대한 처리를 하게 된다. 이때 즉 시그널 에 대한 처리가 끝나지 않은 상태에서 시그널이 발생되면 어떻게 될까 ?
시그널 처리중 동일한 시그널이 들어온다면 이 시그널은 블럭(보류)되었다가 핸들러가 처리를 끝나면 바로 전달된다. 이유는 시그널 이 발생되어서 해당 시그널에 대한 핸들러가 실행되면, 핸들러 실행이 종료되기까지 발생된 시그널에 대해서 block 을 하기 때문이다. 그런데 동일한 시그널이 2개가 발생을 한다면?
커널은 시그널의 대기열을 유지할수 없으므로 마지막에 도착한 시그널은 사라지게 된다.
만약 다른 종류의 시그널이 발생한다면, 그 즉시 시그널이 전달된다. 기존 시그널 핸들러가 작업중이던 말던 그 시점에서 새로운 시그널을 받아들이고, 핸들러를 빠져나가게 된다. 그리고 다시 복귀하지 않는다.
그럼 시그널은 신뢰하기 힘들겠군요?
시그널이 큐잉 되지 않는다는 점은 짧은 시간에 여러개의 시그널이 발생할때 시그널을 잃어버릴수도 있다라는 것을 의미한다. 물론 하나의 프로세스에 대해서 매우 짧은 시간에 시그널이 다수 발생하는 일은 그리 흔하지 않긴 하겠지만 가끔은 문제가 될소지가 있다. 우리가 일반 시그널이 큐잉 되도록 커널을 뜯어 고칠수는 없는 문제이므로, 이걸 완벽하게 해결할수는 없다. 그러나 핸들러를 최소한 아토믹 한 코드로 만듬으로써 이러한 문제의 발생을 줄일수는 있을것이다. 그렇지 않고 커널차원에서 이러한 문제를 해결하고자 한다면 리얼타임 시그널을 사용해야 할것이다.가장 큰 문제는 시그널핸들러 처리중에 다른 종류의 시그널이 발생했을때이다. 위에서 말했듯이 이럴경우 핸들러 처리도중에 빠져나가게 되고, 다시 핸들러로 복귀하지 않게 된다. 이건 꽤 심각할수 있는데, 시그널을 받아서 어떠한 파일 작업을 하고 있는데, 도중에 다른 시그널이 들어와 버리면, 제대로된 파일작업결과를 보증할수 없을것이다.
다행히 Unix 에서는 위의 문제들을 해결할수 있는 시그널 제어 관련 함수들을 제공한다. 이문서의 뒷부분에서 이에 대한 내용을 다루게 될것이다. 다음은 시그널의 이러한 특징을 테스트하기 위한 예제 코드이다.
예제: sigint.c
#include <signal.h> #include <stdio.h> #include <string.h> void sig_int(); void sig_usr(); int main() { char buf[255]; int i= 0; if ((signal(SIGINT, sig_int)) == SIG_ERR) { perror("signal setting error : "); exit(1); } if ((signal(SIGUSR2, sig_usr)) == SIG_ERR) { perror("signal setting error : "); exit(1); } while(1) { printf("%d\n", i); sleep(1); i++; } } void sig_int() { fprintf(stderr, "SIGINT !!!!\n"); sleep(5); } void sig_usr() { fprintf(stderr, "SIGUSR !!!!\n"); } |
[yundream@localhost test]# ./sigtest 1 2 3 |
그럼 이제 sig_int 핸들러를 호출하고 있는도중에 SIGUSR2 시그널을 발생시키면 어떻게 될까 ? 이 테스트는 ./sigtest 를 실행시키고 CTRL+C 를 입력 SIGINT 를 발생시키고, 핸들러를 호출하는 중에 쉘에서 kill 명령을 써서 sigtest 의 pid 로 SIGUSR2 시그널을 보내면 될것이다.
[yundream@localhost test]# ps -aux | grep sigtest yundream 2176 0.0 0.1 1348 344 pts/5 S 23:48 0:00 ./sigtest [yundream@localhost test]# kill -SIGUSR2 2176 |
이러한 문제들의 대한 해법은 이문서의 뒷부분에서 다루도록 하겠다.
signal 관렴함수
지금까지 시그널의 개론적인 면을 살펴봤으니 실제 시그널을 보내고/받고/제어하기 위한 어떤 함수들이 있는지 살펴보도록 하겠다.신호 보내기 함수
Unix 에서는 다음과 같은 신호를 보내기 위한 함수를 제공한다.#include |
raise 는 자기자신에게 sig 시그널을 보내는데, kill(getpid(), sig)로 동일한 일을 할수 있다.
신호 제어 함수
지난번 기사인 signal다루기(1)에서 에제 sig_hup.c 를 컴파일 해서 테스트 해보았다면 새로 execl 된 프로세스에서는 시그널 작동이 제대로 되지 않는다는 것을 알수 있을것이다. 이유는 오늘 내용을 조금 생각해 보면서 읽었다면 충분히 알아낼수 있을것이다. sig_hup 에서 SIGHUP시그널을 전달받아 sig_handler 를 실행시키면, 핸들러가 끝나기 전가지 SIGHUP 를 블럭시키게 된다. 핸들러에서 execl 을 호출하므로 이 핸들러는 절대 종료될수가 없게 된다. 당연히 SIGHUP 시그널은 계속 블럭 된채로 남게 되고, 새로 들어오는 SIGHUP 는 모두 무시되게 된다.이 문제를 해결하기 위해서는 코드가 시작될때 해당 시그널이 블럭되어 있는지 확인해서 블럭을 해제시켜 주면 될것이다. 또한 시그널을 그룹지워서 관리하면 여러개의 시그널을 동시에 관리할수 있음으로 편리할것이다. 이러한 시그널 제어와 그룹핑을 위해서 Unix 는 다음과 같은 함수들을 제공한다.
// 시그널 그룹관리를 위한 함수 int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); int sigaddset(sigset_t *set, int signum); int sigdelset(sigset_t *set, int signum); int sigismember(const sigset-t *set, int signum); // 시그널(그룹) 제어를 위한 함수 int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); int sigpending(sigset_t *set); int sigsuspend(const sigset_t *mask); |
sigemptyset 은 set 이 가르키는 시그널 집합을 초기화 한다.
sigfillset 은 set 이 모든 신호를 포함하도록 초기화 한다.
sigaddset 은 set에 시그널 signum 을 추가한다.
sigdelset 은 set에서 시그널 signum 을 삭제한다.
sigismember 은 set에 시그널 signum 이 포함되어 있는지 검사한다.
sigprocmask 은 시그널 마스크를 검사하고 변경하기 위해서 사용된다. 간단히 말해서 해당 시그널에 대해서 BLOCK, UNBLOCK 를 하기 위해서 사용한다.
sigpending 은 전달된 시그널(대기하고 있는시그널)에 대한 검사를 하기 위해서 사용된다.
sigsuspend 해당 신호가 발생할때까지 프로세스를 중단시킨다.
이상 시그널 그룹관리와 이의 제어를 위한 함수를 알아봤는데, 이 사이트의 목적인 "예제를 통한 이해" 를 위해서 간단한 예제를 준비했다. 이 예제는 signal다루기(1) 의 sig_hup 에서 발견되었던 "시그널블럭" 문제를 위의 함수들을 이용해서 해결하도록 할것이다.
예제: sig_hup2.c
#include <signal.h> #include <unistd.h> void sig_handler(int signo); int main() { int i = 0; sigset_t newmask, oldmask; printf("Program start\n"); if (signal(SIGHUP, (void *)sig_handler) == SIG_ERR) { perror("signal set error "); exit(0) ; } sigemptyset(&newmask); sigaddset(&newmask, SIGHUP); if (sigprocmask(SIG_UNBLOCK, &newmask, &oldmask) < 0) { perror("sigmask error : "); exit(0); } while(1) { printf("%d\n", i); i++; sleep(1); } return 1; } void sig_handler(int signo) { execl("./sig_hup2", 0); } |
신호 받기 함수
지금까지 우리는 신호를 받기 위해서 signal 이라는 함수를 사용했었다.#include |
그러나 현재는 위의 signal 은쓰지 않고 대신 sigaction 함수를 사용한다. signal 은 ANSI C 에 의해서 정의된 함수인데, 신호에 대한 정의가 애매한 불안정한 함수이다. 그러므로 예전쏘쓰와의 호환을 위한 목적이 아니면 사용하지 않도록 한다.
sigaction 은 POSIX.1 에 의해서 제안된 안정된 신호체제를 제공한다.
#include |
struct sigaction { void (*sa_handler)(int); // signum 과 관련된 핸들러 함수 void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; // 시그널 처리동안 블럭되어야할 시그널의 마스크 int sa_flags; // 시그널의 처리 행위 조절을 위한 플래그 void (*sa_restorer)(void); // 사용되지 않는다. } |
마지막으로 "예제: sigint.c" 를 sigaction 버젼으로 작성하고 sigint.c 의 문제점이였던, 시그널 핸들러 실행중 다른 시그널이 들어왔을경우 중단되어 버리는 문제를 해결하도록 코드를 재 작성하였다.
예제: sigint2.c
#include <signal.h> #include <unistd.h> #include <string.h> #include <stdio.h> void sig_int(int signo); void sig_usr(int signo); int main() { int i = 0; struct sigaction intsig, usrsig; usrsig.sa_handler = sig_usr; sigemptyset(&usrsig.sa_mask); usrsig.sa_flags = 0; intsig.sa_handler = sig_int; sigemptyset(&intsig.sa_mask); intsig.sa_flags = 0; if (sigaction(SIGINT, &intsig, 0) == -1) { printf ("signal(SIGALRM) error"); return -1; } if (sigaction(SIGUSR2, &usrsig, 0) == -1) { printf ("signal(SIGUSR2) error"); return -1; } while(1) { printf("%d\n", i); i++; sleep(1); } } void sig_int(int signo) { sigset_t sigset, oldset; sigfillset(&sigset); // 새로들어오는 모든 시그널에 대해서 block 한다. if (sigprocmask(SIG_BLOCK, &sigset, &oldset) < 0) { printf("sigprocmask %d error \n", signo); } fprintf(stderr, "SIGINT !!!!\n"); sleep(5); } void sig_usr(int signo) { printf("sig_usr2\n"); } |
시그널의 특징 : 시그널은 대기열이 없다
시그널은 한 프로세스에 대해서 발생하는 시그널을 큐잉 하지 못한다(대부분의 유닉스). 특정 프로세스에 보내는 시그널은 커널에서 관리하는데 이때 커널은 프로세스에게 보낼 시그널을 한개 이상 유지할수 없다.시그널을 받게 되면, 프로세스는 시그널 핸들러(신호 처리기)를 이용해서 시그널에 대한 처리를 하게 된다. 이때 즉 시그널 에 대한 처리가 끝나지 않은 상태에서 시그널이 발생되면 어떻게 될까 ?
시그널 처리중 동일한 시그널이 들어온다면 이 시그널은 블럭(보류)되었다가 핸들러가 처리를 끝나면 바로 전달된다. 이유는 시그널 이 발생되어서 해당 시그널에 대한 핸들러가 실행되면, 핸들러 실행이 종료되기까지 발생된 시그널에 대해서 block 을 하기 때문이다. 그런데 동일한 시그널이 2개가 발생을 한다면?
커널은 시그널의 대기열을 유지할수 없으므로 마지막에 도착한 시그널은 사라지게 된다.
만약 다른 종류의 시그널이 발생한다면, 그 즉시 시그널이 전달된다. 기존 시그널 핸들러가 작업중이던 말던 그 시점에서 새로운 시그널을 받아들이고, 핸들러를 빠져나가게 된다. 그리고 다시 복귀하지 않는다.
그럼 시그널은 신뢰하기 힘들겠군요?
시그널이 큐잉 되지 않는다는 점은 짧은 시간에 여러개의 시그널이 발생할때 시그널을 잃어버릴수도 있다라는 것을 의미한다. 물론 하나의 프로세스에 대해서 매우 짧은 시간에 시그널이 다수 발생하는 일은 그리 흔하지 않긴 하겠지만 가끔은 문제가 될소지가 있다. 우리가 일반 시그널이 큐잉 되도록 커널을 뜯어 고칠수는 없는 문제이므로, 이걸 완벽하게 해결할수는 없다. 그러나 핸들러를 최소한 아토믹 한 코드로 만듬으로써 이러한 문제의 발생을 줄일수는 있을것이다. 그렇지 않고 커널차원에서 이러한 문제를 해결하고자 한다면 리얼타임 시그널을 사용해야 할것이다.가장 큰 문제는 시그널핸들러 처리중에 다른 종류의 시그널이 발생했을때이다. 위에서 말했듯이 이럴경우 핸들러 처리도중에 빠져나가게 되고, 다시 핸들러로 복귀하지 않게 된다. 이건 꽤 심각할수 있는데, 시그널을 받아서 어떠한 파일 작업을 하고 있는데, 도중에 다른 시그널이 들어와 버리면, 제대로된 파일작업결과를 보증할수 없을것이다.
다행히 Unix 에서는 위의 문제들을 해결할수 있는 시그널 제어 관련 함수들을 제공한다. 이문서의 뒷부분에서 이에 대한 내용을 다루게 될것이다. 다음은 시그널의 이러한 특징을 테스트하기 위한 예제 코드이다.
예제: sigint.c
#include <signal.h> #include <stdio.h> #include <string.h> void sig_int(); void sig_usr(); int main() { char buf[255]; int i= 0; if ((signal(SIGINT, sig_int)) == SIG_ERR) { perror("signal setting error : "); exit(1); } if ((signal(SIGUSR2, sig_usr)) == SIG_ERR) { perror("signal setting error : "); exit(1); } while(1) { printf("%d\n", i); sleep(1); i++; } } void sig_int() { fprintf(stderr, "SIGINT !!!!\n"); sleep(5); } void sig_usr() { fprintf(stderr, "SIGUSR !!!!\n"); } |
[yundream@localhost test]# ./sigtest 1 2 3 |
그럼 이제 sig_int 핸들러를 호출하고 있는도중에 SIGUSR2 시그널을 발생시키면 어떻게 될까 ? 이 테스트는 ./sigtest 를 실행시키고 CTRL+C 를 입력 SIGINT 를 발생시키고, 핸들러를 호출하는 중에 쉘에서 kill 명령을 써서 sigtest 의 pid 로 SIGUSR2 시그널을 보내면 될것이다.
[yundream@localhost test]# ps -aux | grep sigtest yundream 2176 0.0 0.1 1348 344 pts/5 S 23:48 0:00 ./sigtest [yundream@localhost test]# kill -SIGUSR2 2176 |
이러한 문제들의 대한 해법은 이문서의 뒷부분에서 다루도록 하겠다.
signal 관렴함수
지금까지 시그널의 개론적인 면을 살펴봤으니 실제 시그널을 보내고/받고/제어하기 위한 어떤 함수들이 있는지 살펴보도록 하겠다.신호 보내기 함수
Unix 에서는 다음과 같은 신호를 보내기 위한 함수를 제공한다.#include |
raise 는 자기자신에게 sig 시그널을 보내는데, kill(getpid(), sig)로 동일한 일을 할수 있다.
신호 제어 함수
지난번 기사인 signal다루기(1)에서 에제 sig_hup.c 를 컴파일 해서 테스트 해보았다면 새로 execl 된 프로세스에서는 시그널 작동이 제대로 되지 않는다는 것을 알수 있을것이다. 이유는 오늘 내용을 조금 생각해 보면서 읽었다면 충분히 알아낼수 있을것이다. sig_hup 에서 SIGHUP시그널을 전달받아 sig_handler 를 실행시키면, 핸들러가 끝나기 전가지 SIGHUP 를 블럭시키게 된다. 핸들러에서 execl 을 호출하므로 이 핸들러는 절대 종료될수가 없게 된다. 당연히 SIGHUP 시그널은 계속 블럭 된채로 남게 되고, 새로 들어오는 SIGHUP 는 모두 무시되게 된다.이 문제를 해결하기 위해서는 코드가 시작될때 해당 시그널이 블럭되어 있는지 확인해서 블럭을 해제시켜 주면 될것이다. 또한 시그널을 그룹지워서 관리하면 여러개의 시그널을 동시에 관리할수 있음으로 편리할것이다. 이러한 시그널 제어와 그룹핑을 위해서 Unix 는 다음과 같은 함수들을 제공한다.
// 시그널 그룹관리를 위한 함수 int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); int sigaddset(sigset_t *set, int signum); int sigdelset(sigset_t *set, int signum); int sigismember(const sigset-t *set, int signum); // 시그널(그룹) 제어를 위한 함수 int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); int sigpending(sigset_t *set); int sigsuspend(const sigset_t *mask); |
sigemptyset 은 set 이 가르키는 시그널 집합을 초기화 한다.
sigfillset 은 set 이 모든 신호를 포함하도록 초기화 한다.
sigaddset 은 set에 시그널 signum 을 추가한다.
sigdelset 은 set에서 시그널 signum 을 삭제한다.
sigismember 은 set에 시그널 signum 이 포함되어 있는지 검사한다.
sigprocmask 은 시그널 마스크를 검사하고 변경하기 위해서 사용된다. 간단히 말해서 해당 시그널에 대해서 BLOCK, UNBLOCK 를 하기 위해서 사용한다.
sigpending 은 전달된 시그널(대기하고 있는시그널)에 대한 검사를 하기 위해서 사용된다.
sigsuspend 해당 신호가 발생할때까지 프로세스를 중단시킨다.
이상 시그널 그룹관리와 이의 제어를 위한 함수를 알아봤는데, 이 사이트의 목적인 "예제를 통한 이해" 를 위해서 간단한 예제를 준비했다. 이 예제는 signal다루기(1) 의 sig_hup 에서 발견되었던 "시그널블럭" 문제를 위의 함수들을 이용해서 해결하도록 할것이다.
예제: sig_hup2.c
#include <signal.h> #include <unistd.h> void sig_handler(int signo); int main() { int i = 0; sigset_t newmask, oldmask; printf("Program start\n"); if (signal(SIGHUP, (void *)sig_handler) == SIG_ERR) { perror("signal set error "); exit(0) ; } sigemptyset(&newmask); sigaddset(&newmask, SIGHUP); if (sigprocmask(SIG_UNBLOCK, &newmask, &oldmask) < 0) { perror("sigmask error : "); exit(0); } while(1) { printf("%d\n", i); i++; sleep(1); } return 1; } void sig_handler(int signo) { execl("./sig_hup2", 0); } |
신호 받기 함수
지금까지 우리는 신호를 받기 위해서 signal 이라는 함수를 사용했었다.#include |
그러나 현재는 위의 signal 은쓰지 않고 대신 sigaction 함수를 사용한다. signal 은 ANSI C 에 의해서 정의된 함수인데, 신호에 대한 정의가 애매한 불안정한 함수이다. 그러므로 예전쏘쓰와의 호환을 위한 목적이 아니면 사용하지 않도록 한다.
sigaction 은 POSIX.1 에 의해서 제안된 안정된 신호체제를 제공한다.
#include |
struct sigaction { void (*sa_handler)(int); // signum 과 관련된 핸들러 함수 void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; // 시그널 처리동안 블럭되어야할 시그널의 마스크 int sa_flags; // 시그널의 처리 행위 조절을 위한 플래그 void (*sa_restorer)(void); // 사용되지 않는다. } |
마지막으로 "예제: sigint.c" 를 sigaction 버젼으로 작성하고 sigint.c 의 문제점이였던, 시그널 핸들러 실행중 다른 시그널이 들어왔을경우 중단되어 버리는 문제를 해결하도록 코드를 재 작성하였다.
예제: sigint2.c
#include <signal.h> #include <unistd.h> #include <string.h> #include <stdio.h> void sig_int(int signo); void sig_usr(int signo); int main() { int i = 0; struct sigaction intsig, usrsig; usrsig.sa_handler = sig_usr; sigemptyset(&usrsig.sa_mask); usrsig.sa_flags = 0; intsig.sa_handler = sig_int; sigemptyset(&intsig.sa_mask); intsig.sa_flags = 0; if (sigaction(SIGINT, &intsig, 0) == -1) { printf ("signal(SIGALRM) error"); return -1; } if (sigaction(SIGUSR2, &usrsig, 0) == -1) { printf ("signal(SIGUSR2) error"); return -1; } while(1) { printf("%d\n", i); i++; sleep(1); } } void sig_int(int signo) { sigset_t sigset, oldset; sigfillset(&sigset); // 새로들어오는 모든 시그널에 대해서 block 한다. if (sigprocmask(SIG_BLOCK, &sigset, &oldset) < 0) { printf("sigprocmask %d error \n", signo); } fprintf(stderr, "SIGINT !!!!\n"); sleep(5); } void sig_usr(int signo) { printf("sig_usr2\n"); } |
NCURSES Programming HOWTO ¶
#! v1.7.1, 2002-06-25 Revision History Revision 1.7.1 2002-06-25 Revised by: ppadala Added a README file for building and instructions for building from source. Revision 1.7 2002-06-25 Revised by: ppadala Added "Other formats" section and made lot of fancy changes to the programs. Inlining of programs is gone. Revision 1.6.1 2002-02-24 Revised by: ppadala Removed the old Changelog section, cleaned the makefiles Revision 1.6 2002-02-16 Revised by: ppadala Corrected lot of spelling mistakes, added ACS variables section Revision 1.5 2002-01-05 Revised by: ppadala Changed structure to present proper TOC Revision 1.3.1 2001-07-26 Revised by: ppadala Corrected maintainers paragraph, Corrected stable release number Revision 1.3 2001-07-24 Revised by: ppadala Added copyright notice(LDP license) to main document, Put copyright notice (GPL) for programs as well, Corrected printw_example. Revision 1.2 2001-06-05 Revised by: ppadala Incorporated ravi's changes. Mainly to introduction, menu, form, justforfun sections Revision 1.1 2001-05-22 Revised by: ppadala Added "a word about window" section, Added scanw_example.
-
- 1 NCURSES Programming HOWTO
-
- 1.1 Introduction
- 1.2 The Hello World 프로그램
- 1.3 The Gory Details
- 1.4 초기화
- 1.5 윈도우에 관해
- 1.6 printw() 같은 출력 함수에 대해
- 1.7 scanw() 같은 입력함수에 대해
- 1.8 속성
- 1.9 윈도우 함수의 모든 것
- 1.10 색상에 대해서
- 1.11 키 입력 다루기. 펑션키, 방향키 등을 어떻게 입력받는가.
- 1.12 마우스 처리하기
- 1.13 화면 제어
- 1.14 그외 기능들
- 1.15 그외 라이브러리들
- 1.16 패널 라이브러리
- 1.17 메뉴 라이브러리
- 1.18 폼 라이브러리
- 1.19 툴과 위젯 라이브러리들
- 1.20 Just For Fun !!!
1.1 Introduction ¶
echo "^[[0;31;40mIn Color"
echo "^[[0;37;40m"
1.1.1 NCURSES 란 무엇인가? ¶
1.1.2 NCURSES 로 무엇을 할 수 있는가? ¶
1.1.3 어디서 그것을 구하는가? ¶
tar zxvf ncurses<version>.tar.gz # unzip and untar the archive cd ncurses<version> # cd to the directory ./configure # configure the build according to your # environment make # make it su root # become root make install # install it
rpm -i <downloaded rpm>
1.1.4 문서의 목적 및 범위 ¶
1.1.5 프로그램들에 대해 ¶
#! ncurses | |----> <a class='nonexistent' href='/wiki.php/JustForFun'>?</a>JustForFun -- just for fun programs |----> basics -- basic programs |----> demo -- output files go into this directory after make | | | |----> exe -- exe files of all example programs |----> forms -- programs related to form library |----> menus -- programs related to menus library |----> panels -- programs related to panels library |----> Makefile -- the top level Makefile |----> README -- the top level README file. contains instructions |----> COPYING -- copyright notice
#! <a class='nonexistent' href='/wiki.php/JustForFun'>?</a>JustForFun | |----> hanoi.c -- The Towers of Hanoi Solver |----> life.c -- The Game of Life demo |----> magic.c -- An Odd Order Magic Square builder |----> queens.c -- The famous N-Queens Solver |----> shuffle.c -- A fun game, if you have time to kill |----> tt.c -- A very trivial typing tutor basics | |----> acs_vars.c -- ACS_ variables example |----> hello_world.c -- Simple "Hello World" Program |----> init_func_example.c -- Initialization functions example |----> key_code.c -- Shows the scan code of the key pressed |----> mouse_menu.c -- A menu accessible by mouse |----> other_border.c -- Shows usage of other border functions apa | -- rt from box() |----> printw_example.c -- A very simple printw() example |----> scanw_example.c -- A very simple getstr() example |----> simple_attr.c -- A program that can print a c file with | -- comments in attribute |----> simple_color.c -- A simple example demonstrating colors |----> simple_key.c -- A menu accessible with keyboard UP, DOWN | -- arrows |----> temp_leave.c -- Demonstrates temporarily leaving curses mode |----> win_border.c -- Shows Creation of windows and borders |----> with_chgat.c -- chgat() usage example forms | |----> form_attrib.c -- Usage of field attributes |----> form_options.c -- Usage of field options |----> form_simple.c -- A simple form example |----> form_win.c -- Demo of windows associated with forms menus | |----> menu_attrib.c -- Usage of menu attributes |----> menu_item_data.c -- Usage of item_name() etc.. functions |----> menu_multi_column.c -- Creates multi columnar menus |----> menu_scroll.c -- Demonstrates scrolling capability of menus |----> menu_simple.c -- A simple menu accessed by arrow keys |----> menu_toggle.c -- Creates multi valued menus and explains | -- REQ_TOGGLE_ITEM |----> menu_userptr.c -- Usage of user pointer |----> menu_win.c -- Demo of windows associated with menus panels | |----> panel_browse.c -- Panel browsing through tab. Usage of user | -- pointer |----> panel_hide.c -- Hiding and Un hiding of panels |----> panel_resize.c -- Moving and resizing of panels |----> panel_simple.c -- A simple panel example
1.1.6.2 소스로 부터 빌드하기 ¶
http://cvsview.tldp.org/index.cgi/LDP/howto/docbook/ NCURSES-HOWTO/ncurses_programs.tar.gz
tar zxvf ncurses_programs.tar.gz
jade -t sgml -i html -d <docbook html 스타일 시트의 경로> NCURSES-Programming-HOWTO.sgml
jade -t sgml -i html -d <docbook html 스타일 시트의 경로> -V nochunks NCURSES-Programming-HOWTO.sgml > NCURSES-ONE-BIG-FILE.html
htmldoc --size universal -t pdf --firstpage p1 -f <output file name.pdf> NCURSES-ONE-BIG-FILE.html
htmldoc --size universal -t ps --firstpage p1 -f <출력 파일 이름> NCURSES-ONE-BIG-FILE.html
1.1.7 크레디트 ¶
1.1.8 Wish List ¶
- Add examples to last parts of forms section. (I am working on it)
- Prepare a Demo showing all the programs and allow the user to browse
- Add debug info. _tracef, _tracemouse stuff.
- Accessing termcap, terminfo using functions provided by ncurses package.
- Working on two terminals simultaneously.
- Add things in miscellaneous section.
1.1.9 Copyright ¶
1.2 The Hello World 프로그램 ¶
1.2.1 Ncurses 라이브러리와 같이 컴파일 하기 ¶
#include <ncurses.h> . . . compile and link: gcc <program file> -lncurses
#include <ncurses.h> int main() { initscr(); /* Start curses mode */ printw("Hello World !!!"); /* Print Hello World */ refresh(); /* Print it on to the real screen */ getch(); /* Wait for user input */ endwin(); /* End curses mode */ return 0; }
1.2.2 분석 ¶
1.2.2.1 initscr() 에 대해 ¶
1.2.2.2 신기한 refresh() ¶
1.2.2.3 endwin() 에 대해 ¶
1.3 The Gory Details ¶
1.4 초기화 ¶
1.4.2 raw() 와 cbreak() ¶
1.4.3 echo() 와 noecho() ¶
1.4.4 keypad() ¶
1.4.5 halfdelay() ¶
1.4.6 그외 잡다한 초기화 함수들 ¶
1.4.7 예제 ¶
#include <ncurses.h> int main() { int ch; initscr(); /* Start curses mode */ raw(); /* Line buffering disabled */ keypad(stdscr, TRUE); /* We get F1, F2 etc.. */ noecho(); /* Don't echo() while we do getch */ printw("Type any character to see it in bold\n"); ch = getch(); /* If raw() hadn't been called * we have to press enter before it * gets to the program */ if(ch == KEY_F(1)) /* Without keypad enabled this will */ printw("F1 Key pressed");/* not get to us either */ /* Without noecho() some ugly escape * charachters might have been printed * on screen */ else { printw("The pressed key is "); attron(A_BOLD); printw("%c", ch); attroff(A_BOLD); } refresh(); /* Print it on to the real screen */ getch(); /* Wait for user input */ endwin(); /* End curses mode */ return 0; }
1.5 윈도우에 관해 ¶
printw("Hi There !!!"); refresh();
wprintw(win, "Hi There !!!"); wrefresh(win);
printw(string); /* Print on stdscr at present cursor position */ mvprintw(y, x, string);/* Move to (y, x) then print string */ wprintw(win, string); /* Print on window win at present cursor position */ /* in the window */ mvwprintw(win, y, x, string); /* Move to (y, x) relative to window */ /* co-ordinates and then print */
1.6 printw() 같은 출력 함수에 대해 ¶
- addch() class: Print single character with attributes
- printw() class: Print formatted output similar to printf()
- addstr() class: Print strings
1.6.1 addch() 류의 함수들 ¶
- 한 문자에 원하는 속성 매크로들을 OR 해주는 방법이다. 이 속성 매크로들은 ncurses.h 에서 찾을 수 있다. 예를 들어 굵고 밑줄이 그어진 문자 ch 를 찍고 싶다면 addch() 함수를 다음과 같이 호출하면 된다.
addch(ch | A_BOLD | A_UNDERLINE);
- attrset(), attron(), attroff() 와 같은 함수를 쓰는 방법이다. 이 함수들은 Attributes 섹션에서 설명한다. 간단히 말하면, 이것들은 주어진 윈도우의 속성을 조절한다. 한번 설정되면, 그것이 꺼지기 전까지는 그 윈도우 안에서 찍히는 문자들은 주어진 속성대로 출력된다.
1.6.2 mvaddch(), waddch() 와 mvwaddch() ¶
move(row,col); /* moves the cursor to rowth row and colth column */ addch(ch); can be replaced by mvaddch(row,col,ch);
1.6.3.1 printw() 와 mvprintw ¶
1.6.3.4 간단한 printw 예제 ¶
#include <ncurses.h> /* ncurses.h includes stdio.h */ #include <string.h> int main() { char mesg[]="Just a string"; /* message to be appeared on the screen */ int row,col; /* to store the number of rows and * * the number of colums of the screen */ initscr(); /* start the curses mode */ getmaxyx(stdscr,row,col); /* get the number of rows and columns */ mvprintw(row/2,(col-strlen(mesg))/2,"%s",mesg); /* print the message at the center of the screen */ mvprintw(row-2,0,"This screen has %d rows and %d columns\n",row,col); printw("Try resizing your window(if possible) and then run this program again"); refresh(); getch(); endwin(); return 0; }
1.6.4 addstr() 류의 함수들 ¶
1.6.5 주의 사항 ¶
1.7 scanw() 같은 입력함수에 대해 ¶
- getch() class: Get a character
- scanw() class: Get formatted input
- getstr() class: Get strings
1.7.1 getch() 류의 함수들 ¶
1.7.2.1 scanw() 와 mvscanw ¶
1.7.3 getstr() 류의 함수들 ¶
1.7.4 몇몇 예제 ¶
#include <ncurses.h> /* ncurses.h includes stdio.h */ #include <string.h> int main() { char mesg[]="Enter a string: "; /* message to be appeared on the screen */ char str[80]; int row,col; /* to store the number of rows and * * the number of colums of the screen */ initscr(); /* start the curses mode */ getmaxyx(stdscr,row,col); /* get the number of rows and columns */ mvprintw(row/2,(col-strlen(mesg))/2,"%s",mesg); /* print the message at the center of the screen */ getstr(str); mvprintw(LINES - 2, 0, "You Entered: %s", str); getch(); endwin(); return 0; }
1.8 속성 ¶
#include <ncurses.h> int main(int argc, char *argv[]) { int ch, prev; FILE *fp; int goto_prev = FALSE, y, x; if(argc != 2) { printf("Usage: %s <a c file name>\n", argv[0]); exit(1); } fp = fopen(argv[1], "r"); if(fp == NULL) { perror("Cannot open input file"); exit(1); } initscr(); /* Start curses mode */ prev = EOF; while((ch = fgetc(fp)) != EOF) { if(prev == '/' && ch == '*') /* If it is / and * then olny * switch bold on */ { attron(A_BOLD); goto_prev = TRUE; /* Go to previous char / and * print it in BOLD */ } if(goto_prev == TRUE) { getyx(stdscr, y, x); move(y, x - 1); printw("%c%c", '/', ch); /* The actual printing is done * here */ ch = 'a'; /* 'a' is just a dummy * character to prevent */ // "/*/" comments. goto_prev = FALSE; /* Set it to FALSE or every * thing from here will be / */ } else printw("%c", ch); refresh(); if(prev == '*' && ch == '/') attroff(A_BOLD); /* Switch it off once we got * and then / */ prev = ch; } getch(); endwin(); /* End curses mode */ return 0; }
1.8.1 세부 사항 ¶
#! A_NORMAL Normal display (no highlight) A_STANDOUT Best highlighting mode of the terminal. A_UNDERLINE Underlining A_REVERSE Reverse video A_BLINK Blinking A_DIM Half bright A_BOLD Extra bright or bold A_PROTECT Protected mode A_INVIS Invisible or blank mode A_ALTCHARSET Alternate character set A_CHARTEXT Bit-mask to extract a character COLOR_PAIR(n) Color-pair number n
attron(A_REVERSE | A_BLINK);
1.8.2 attron() 대 attrset() ¶
1.8.3 attr_get() ¶
1.8.4 attr_ 함수들 ¶
1.8.5 wattr 함수들 ¶
1.8.6 chgat() 함수들 ¶
chgat(-1, A_REVERSE, 0, NULL);
#include <ncurses.h> int main(int argc, char *argv[]) { initscr(); /* Start curses mode */ start_color(); /* Start color functionality */ init_pair(1, COLOR_CYAN, COLOR_BLACK); printw("A Big string which i didn't care to type fully "); mvchgat(0, 0, -1, A_BLINK, 1, NULL); /* * First two parameters specify the position at which to start * Third parameter number of characters to update. -1 means till * end of line * Forth parameter is the normal attribute you wanted to give * to the charcter * Fifth is the color index. It is the index given during init_pair() * use 0 if you didn't want color * Sixth one is always NULL */ refresh(); getch(); endwin(); /* End curses mode */ return 0; }
1.9 윈도우 함수의 모든 것 ¶
1.9.1 개괄 ¶
1.9.2 윈도우가 있으라 !!! ¶
#include <ncurses.h> WINDOW *create_newwin(int height, int width, int starty, int startx); void destroy_win(WINDOW *local_win); int main(int argc, char *argv[]) { WINDOW *my_win; int startx, starty, width, height; int ch; initscr(); /* Start curses mode */ cbreak(); /* Line buffering disabled, Pass on * everty thing to me */ keypad(stdscr, TRUE); /* I need that nifty F1 */ height = 3; width = 10; starty = (LINES - height) / 2; /* Calculating for a center placement */ startx = (COLS - width) / 2; /* of the window */ printw("Press F1 to exit"); refresh(); my_win = create_newwin(height, width, starty, startx); while((ch = getch()) != KEY_F(1)) { switch(ch) { case KEY_LEFT: destroy_win(my_win); my_win = create_newwin(height, width, starty,--startx); break; case KEY_RIGHT: destroy_win(my_win); my_win = create_newwin(height, width, starty,++startx); break; case KEY_UP: destroy_win(my_win); my_win = create_newwin(height, width, --starty,startx); break; case KEY_DOWN: destroy_win(my_win); my_win = create_newwin(height, width, ++starty,startx); break; } } endwin(); /* End curses mode */ return 0; } WINDOW *create_newwin(int height, int width, int starty, int startx) { WINDOW *local_win; local_win = newwin(height, width, starty, startx); box(local_win, 0 , 0); /* 0, 0 gives default characters * for the vertical and horizontal * lines */ wrefresh(local_win); /* Show that box */ return local_win; } void destroy_win(WINDOW *local_win) { /* box(local_win, ' ', ' '); : This won't produce the desired * result of erasing the window. It will leave it's four corners * and so an ugly remnant of window. */ wborder(local_win, ' ', ' ', ' ',' ',' ',' ',' ',' '); /* The parameters taken are * 1. win: the window on which to operate * 2. ls: character to be used for the left side of the window * 3. rs: character to be used for the right side of the window * 4. ts: character to be used for the top side of the window * 5. bs: character to be used for the bottom side of the window * 6. tl: character to be used for the top left corner of the window * 7. tr: character to be used for the top right corner of the window * 8. bl: character to be used for the bottom left corner of the window * 9. br: character to be used for the bottom right corner of the window */ wrefresh(local_win); delwin(local_win); }
1.9.3 설명 ¶
wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');
#! +-----------------------+ | | | | | | | | | | | | +-----------------------+
1.9.4 예제의 다른 부분 ¶
1.9.5 다른 테두리 함수들 ¶
#include <ncurses.h> typedef struct _win_border_struct { chtype ls, rs, ts, bs, tl, tr, bl, br; }WIN_BORDER; typedef struct _WIN_struct { int startx, starty; int height, width; WIN_BORDER border; }WIN; void init_win_params(WIN *p_win); void print_win_params(WIN *p_win); void create_box(WIN *win, int bool); int main(int argc, char *argv[]) { WIN win; int ch; initscr(); /* Start curses mode */ start_color(); /* Start the color functionality */ cbreak(); /* Line buffering disabled, Pass on * everty thing to me */ keypad(stdscr, TRUE); /* I need that nifty F1 */ noecho(); init_pair(1, COLOR_CYAN, COLOR_BLACK); /* Initialize the window parameters */ init_win_params(&win); print_win_params(&win); attron(COLOR_PAIR(1)); printw("Press F1 to exit"); refresh(); attroff(COLOR_PAIR(1)); create_box(&win, TRUE); while((ch = getch()) != KEY_F(1)) { switch(ch) { case KEY_LEFT: create_box(&win, FALSE); --win.startx; create_box(&win, TRUE); break; case KEY_RIGHT: create_box(&win, FALSE); ++win.startx; create_box(&win, TRUE); break; case KEY_UP: create_box(&win, FALSE); --win.starty; create_box(&win, TRUE); break; case KEY_DOWN: create_box(&win, FALSE); ++win.starty; create_box(&win, TRUE); break; } } endwin(); /* End curses mode */ return 0; } void init_win_params(WIN *p_win) { p_win->height = 3; p_win->width = 10; p_win->starty = (LINES - p_win->height)/2; p_win->startx = (COLS - p_win->width)/2; p_win->border.ls = '|'; p_win->border.rs = '|'; p_win->border.ts = '-'; p_win->border.bs = '-'; p_win->border.tl = '+'; p_win->border.tr = '+'; p_win->border.bl = '+'; p_win->border.br = '+'; } void print_win_params(WIN *p_win) { #ifdef _DEBUG mvprintw(25, 0, "%d %d %d %d", p_win->startx, p_win->starty, p_win->width, p_win->height); refresh(); #endif } void create_box(WIN *p_win, int bool) { int i, j; int x, y, w, h; x = p_win->startx; y = p_win->starty; w = p_win->width; h = p_win->height; if(bool == TRUE) { mvaddch(y, x, p_win->border.tl); mvaddch(y, x + w, p_win->border.tr); mvaddch(y + h, x, p_win->border.bl); mvaddch(y + h, x + w, p_win->border.br); mvhline(y, x + 1, p_win->border.ts, w - 1); mvhline(y + h, x + 1, p_win->border.bs, w - 1); mvvline(y + 1, x, p_win->border.ls, h - 1); mvvline(y + 1, x + w, p_win->border.rs, h - 1); } else for(j = y; j <= y + h; ++j) for(i = x; i <= x + w; ++i) mvaddch(j, i, ' '); refresh(); }
1.10.1 개괄 ¶
#include <ncurses.h> void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string); int main(int argc, char *argv[]) { initscr(); /* Start curses mode */ if(has_colors() == FALSE) { endwin(); printf("You terminal does not support color\n"); exit(1); } start_color(); /* Start color */ init_pair(1, COLOR_RED, COLOR_BLACK); attron(COLOR_PAIR(1)); print_in_middle(stdscr, LINES / 2, 0, 0, "Viola !!! In color ..."); attroff(COLOR_PAIR(1)); getch(); endwin(); } void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string) { int length, x, y; float temp; if(win == NULL) win = stdscr; getyx(win, y, x); if(startx != 0) x = startx; if(starty != 0) y = starty; if(width == 0) width = 80; length = strlen(string); temp = (width - length)/ 2; x = startx + (int)temp; mvwprintw(win, y, x, "%s", string); refresh(); }
#! COLOR_BLACK 0 COLOR_RED 1 COLOR_GREEN 2 COLOR_YELLOW 3 COLOR_BLUE 4 COLOR_MAGENTA 5 COLOR_CYAN 6 COLOR_WHITE 7
1.10.2 색상 정의 바꾸기 ¶
init_color(COLOR_RED, 700, 0, 0); /* param 1 : color name * param 2, 3, 4 : rgb content min = 0, max = 1000 */
1.11.1 개괄 ¶
int ch; ch = getch();
if(ch == KEY_LEFT) printw("Left arrow is pressed\n");
1.11.2 간단한 키 사용 예제 ¶
#include <stdio.h> #include <ncurses.h> #define WIDTH 30 #define HEIGHT 10 int startx = 0; int starty = 0; char *choices[] = { "Choice 1", "Choice 2", "Choice 3", "Choice 4", "Exit", }; int n_choices = sizeof(choices) / sizeof(char *); void print_menu(WINDOW *menu_win, int highlight); int main() { WINDOW *menu_win; int highlight = 1; int choice = 0; int c; initscr(); clear(); noecho(); cbreak(); /* Line buffering disabled. pass on everything */ startx = (80 - WIDTH) / 2; starty = (24 - HEIGHT) / 2; menu_win = newwin(HEIGHT, WIDTH, starty, startx); keypad(menu_win, TRUE); mvprintw(0, 0, "Use arrow keys to go up and down, Press enter to select a choice"); refresh(); print_menu(menu_win, highlight); while(1) { c = wgetch(menu_win); switch(c) { case KEY_UP: if(highlight == 1) highlight = n_choices; else --highlight; break; case KEY_DOWN: if(highlight == n_choices) highlight = 1; else ++highlight; break; case 10: choice = highlight; break; default: mvprintw(24, 0, "Charcter pressed is = %3d Hopefully it can be printed as '%c'", c, c); refresh(); break; } print_menu(menu_win, highlight); if(choice != 0) /* User did a choice come out of the infinite loop */ break; } mvprintw(23, 0, "You chose choice %d with choice string %s\n", choice, choices[choice - 1]); clrtoeol(); refresh(); endwin(); return 0; } void print_menu(WINDOW *menu_win, int highlight) { int x, y, i; x = 2; y = 2; box(menu_win, 0, 0); for(i = 0; i < n_choices; ++i) { if(highlight == i + 1) /* High light the present choice */ { wattron(menu_win, A_REVERSE); mvwprintw(menu_win, y, x, "%s", choices[i]); wattroff(menu_win, A_REVERSE); } else mvwprintw(menu_win, y, x, "%s", choices[i]); ++y; } wrefresh(menu_win); }
1.12 마우스 처리하기 ¶
1.12.1 개괄 ¶
mousemask( mmask_t newmask, /* The events you want to listen to */ mmask_t *oldmask) /* The old events mask */
#! Name Description --------------------------------------------------------------------- BUTTON1_PRESSED mouse button 1 down BUTTON1_RELEASED mouse button 1 up BUTTON1_CLICKED mouse button 1 clicked BUTTON1_DOUBLE_CLICKED mouse button 1 double clicked BUTTON1_TRIPLE_CLICKED mouse button 1 triple clicked BUTTON2_PRESSED mouse button 2 down BUTTON2_RELEASED mouse button 2 up BUTTON2_CLICKED mouse button 2 clicked BUTTON2_DOUBLE_CLICKED mouse button 2 double clicked BUTTON2_TRIPLE_CLICKED mouse button 2 triple clicked BUTTON3_PRESSED mouse button 3 down BUTTON3_RELEASED mouse button 3 up BUTTON3_CLICKED mouse button 3 clicked BUTTON3_DOUBLE_CLICKED mouse button 3 double clicked BUTTON3_TRIPLE_CLICKED mouse button 3 triple clicked BUTTON4_PRESSED mouse button 4 down BUTTON4_RELEASED mouse button 4 up BUTTON4_CLICKED mouse button 4 clicked BUTTON4_DOUBLE_CLICKED mouse button 4 double clicked BUTTON4_TRIPLE_CLICKED mouse button 4 triple clicked BUTTON_SHIFT shift was down during button state change BUTTON_CTRL control was down during button state change BUTTON_ALT alt was down during button state change ALL_MOUSE_EVENTS report all button state changes REPORT_MOUSE_POSITION report mouse movement
1.12.2 이벤트 받아오기 ¶
MEVENT event; ch = getch(); if(ch == KEY_MOUSE) if(getmouse(&event) == OK) . /* Do some thing with the event */ . .
typedef struct { short id; /* ID to distinguish multiple devices */ int x, y, z; /* event coordinates */ mmask_t bstate; /* button state bits */ }
if(event.bstate & BUTTON1_PRESSED) printw("Left Button Pressed");
1.12.3 전부 실습해보자 ¶
#include <ncurses.h> #define WIDTH 30 #define HEIGHT 10 int startx = 0; int starty = 0; char *choices[] = { "Choice 1", "Choice 2", "Choice 3", "Choice 4", "Exit", }; int n_choices = sizeof(choices) / sizeof(char *); void print_menu(WINDOW *menu_win, int highlight); void report_choice(int mouse_x, int mouse_y, int *p_choice); int main() { int c, choice = 0; WINDOW *menu_win; MEVENT event; /* Initialize curses */ initscr(); clear(); noecho(); cbreak(); //Line buffering disabled. pass on everything /* Try to put the window in the middle of screen */ startx = (80 - WIDTH) / 2; starty = (24 - HEIGHT) / 2; attron(A_REVERSE); mvprintw(23, 1, "Click on Exit to quit (Works best in a virtual console)"); refresh(); attroff(A_REVERSE); /* Print the menu for the first time */ menu_win = newwin(HEIGHT, WIDTH, starty, startx); print_menu(menu_win, 1); /* Get all the mouse events */ mousemask(ALL_MOUSE_EVENTS, NULL); while(1) { c = wgetch(menu_win); switch(c) { case KEY_MOUSE: if(getmouse(&event) == OK) { /* When the user clicks left mouse button */ if(event.bstate & BUTTON1_PRESSED) { report_choice(event.x + 1, event.y + 1, &choice); if(choice == -1) //Exit chosen goto end; mvprintw(22, 1, "Choice made is : %d String Chosen is \"%10s\"", choice, choices[choice - 1]); refresh(); } } print_menu(menu_win, choice); break; } } end: endwin(); return 0; } void print_menu(WINDOW *menu_win, int highlight) { int x, y, i; x = 2; y = 2; box(menu_win, 0, 0); for(i = 0; i < n_choices; ++i) { if(highlight == i + 1) { wattron(menu_win, A_REVERSE); mvwprintw(menu_win, y, x, "%s", choices[i]); wattroff(menu_win, A_REVERSE); } else mvwprintw(menu_win, y, x, "%s", choices[i]); ++y; } wrefresh(menu_win); } /* Report the choice according to mouse position */ void report_choice(int mouse_x, int mouse_y, int *p_choice) { int i,j, choice; i = startx + 2; j = starty + 3; for(choice = 0; choice < n_choices; ++choice) if(mouse_y == j + choice && mouse_x >= i && mouse_x <= i + strlen(choices[choice])) { if(choice == n_choices - 1) *p_choice = -1; else *p_choice = choice + 1; break; } }
1.12.4 그외 잡다한 함수들 ¶
1.13.1 getyx() 함수들 ¶
getyx(win, y, x); /* win: window pointer * y, x: y, x co-ordinates will be put into this variables */
1.13.2 화면 덤프 ¶
1.13.3 윈도우 덤프 ¶
1.14 그외 기능들 ¶
1.14.1 curs_set() ¶
#! 0 : invisible or 1 : normal or 2 : very visible.
1.14.2 일시적으로 curses 모드 나가기 ¶
#include <ncurses.h> int main() { initscr(); /* Start curses mode */ printw("Hello World !!!\n"); /* Print Hello World */ refresh(); /* Print it on to the real screen */ def_prog_mode(); /* Save the tty modes */ endwin(); /* End curses mode temporarily */ system("/bin/sh"); /* Do whatever you like in cooked mode */ reset_prog_mode(); /* Return to the previous tty mode*/ /* stored by def_prog_mode() */ refresh(); /* Do refresh() to restore the */ /* Screen contents */ printw("Another String\n"); /* Back to curses use the full */ refresh(); /* capabilities of curses */ endwin(); /* End curses mode */ return 0; }
1.14.3 ACS_ 변수들 ¶
#include <ncurses.h> int main() { initscr(); printw("Upper left corner "); addch(ACS_ULCORNER); printw("\n"); printw("Lower left corner "); addch(ACS_LLCORNER); printw("\n"); printw("Lower right corner "); addch(ACS_LRCORNER); printw("\n"); printw("Tee pointing right "); addch(ACS_LTEE); printw("\n"); printw("Tee pointing left "); addch(ACS_RTEE); printw("\n"); printw("Tee pointing up "); addch(ACS_BTEE); printw("\n"); printw("Tee pointing down "); addch(ACS_TTEE); printw("\n"); printw("Horizontal line "); addch(ACS_HLINE); printw("\n"); printw("Vertical line "); addch(ACS_VLINE); printw("\n"); printw("Large Plus or cross over "); addch(ACS_PLUS); printw("\n"); printw("Scan Line 1 "); addch(ACS_S1); printw("\n"); printw("Scan Line 3 "); addch(ACS_S3); printw("\n"); printw("Scan Line 7 "); addch(ACS_S7); printw("\n"); printw("Scan Line 9 "); addch(ACS_S9); printw("\n"); printw("Diamond "); addch(ACS_DIAMOND); printw("\n"); printw("Checker board (stipple) "); addch(ACS_CKBOARD); printw("\n"); printw("Degree Symbol "); addch(ACS_DEGREE); printw("\n"); printw("Plus/Minus Symbol "); addch(ACS_PLMINUS); printw("\n"); printw("Bullet "); addch(ACS_BULLET); printw("\n"); printw("Arrow Pointing Left "); addch(ACS_LARROW); printw("\n"); printw("Arrow Pointing Right "); addch(ACS_RARROW); printw("\n"); printw("Arrow Pointing Down "); addch(ACS_DARROW); printw("\n"); printw("Arrow Pointing Up "); addch(ACS_UARROW); printw("\n"); printw("Board of squares "); addch(ACS_BOARD); printw("\n"); printw("Lantern Symbol "); addch(ACS_LANTERN); printw("\n"); printw("Solid Square Block "); addch(ACS_BLOCK); printw("\n"); printw("Less/Equal sign "); addch(ACS_LEQUAL); printw("\n"); printw("Greater/Equal sign "); addch(ACS_GEQUAL); printw("\n"); printw("Pi "); addch(ACS_PI); printw("\n"); printw("Not equal "); addch(ACS_NEQUAL); printw("\n"); printw("UK pound sign "); addch(ACS_STERLING); printw("\n"); refresh(); getch(); endwin(); return 0; }
1.15 그외 라이브러리들 ¶
1.16 패널 라이브러리 ¶
1.16.1 개괄 ¶
- 패널에 붙여질 윈도우를 생성한다. (newwin() 사용)
- 이제 보여지는 순서대로 패널을 생성한다. 보여지기 원하는 순서대로 그것들을 쌓아라. new_panel() 함수를 쓰면 패널을 만들 수 있다.
- update_panels() 함수를 호출하여 패널들을 가상의 화면에 맞는 순서대로 보여지도록 업데이트한다. 그 다음 doupdate() 를 호출하여 실제 화면에 나타나도록 한다.
- show_panel(), hide_panel(), move_panel() 등의 함수를 사용하여 패널들을 다룬다. panel_hidden() 과 panel_window() 와 같은 보조 함수를 사용해라. 패널에 쓰이는 설정 정보들을 저장하기 위해서 사용자 포인터 를 사용하라. set_panel_useptr() 과 panel_userptr() 함수를 패널에 사용자 포인터를 설정하고 얻어오는데 쓸 수 있을 것이다.
- 패널을 더 이상 쓰지 않게되면, del_panel() 을 사용하여 그것을 지운다.
1.16.2 패널 라이브러리와 컴파일 하기 ¶
#! #include <panel.h> . . . compile and link: gcc <program file> -lpanel -lncurses
#include <panel.h> int main() { WINDOW *my_wins[3]; PANEL *my_panels[3]; int lines = 10, cols = 40, y = 2, x = 4, i; initscr(); cbreak(); noecho(); /* Create windows for the panels */ my_wins[0] = newwin(lines, cols, y, x); my_wins[1] = newwin(lines, cols, y + 1, x + 5); my_wins[2] = newwin(lines, cols, y + 2, x + 10); /* * Create borders around the windows so that you can see the effect * of panels */ for(i = 0; i < 3; +++i) box(my_wins[i], 0, 0); /* Attach a panel to each window */ /* Order is bottom up */ my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */ my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */ my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */ /* Update the stacking order. 2nd panel will be on top */ update_panels(); /* Show it on the screen */ doupdate(); getch(); endwin(); }
1.16.3 패널 윈도우 탐색 ¶
#include <panel.h> #define NLINES 10 #define NCOLS 40 void init_wins(WINDOW **wins, int n); void win_show(WINDOW *win, char *label, int label_color); void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color); int main() { WINDOW *my_wins[3]; PANEL *my_panels[3]; PANEL *top; int ch; /* Initialize curses */ initscr(); start_color(); cbreak(); noecho(); keypad(stdscr, TRUE); /* Initialize all the colors */ init_pair(1, COLOR_RED, COLOR_BLACK); init_pair(2, COLOR_GREEN, COLOR_BLACK); init_pair(3, COLOR_BLUE, COLOR_BLACK); init_pair(4, COLOR_CYAN, COLOR_BLACK); init_wins(my_wins, 3); /* Attach a panel to each window */ /* Order is bottom up */ my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */ my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */ my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */ /* Set up the user pointers to the next panel */ set_panel_userptr(my_panels[0], my_panels[1]); set_panel_userptr(my_panels[1], my_panels[2]); set_panel_userptr(my_panels[2], my_panels[0]); /* Update the stacking order. 2nd panel will be on top */ update_panels(); /* Show it on the screen */ attron(COLOR_PAIR(4)); mvprintw(LINES - 2, 0, "Use tab to browse through the windows (F1 to Exit)"); attroff(COLOR_PAIR(4)); doupdate(); top = my_panels[2]; while((ch = getch()) != KEY_F(1)) { switch(ch) { case 9: top = (PANEL *)panel_userptr(top); top_panel(top); break; } update_panels(); doupdate(); } endwin(); return 0; } /* Put all the windows */ void init_wins(WINDOW **wins, int n) { int x, y, i; char label[80]; y = 2; x = 10; for(i = 0; i < n; ++i) { wins[i] = newwin(NLINES, NCOLS, y, x); sprintf(label, "Window Number %d", i + 1); win_show(wins[i], label, i + 1); y += 3; x += 7; } } /* Show the window with a border and a label */ void win_show(WINDOW *win, char *label, int label_color) { int startx, starty, height, width; getbegyx(win, starty, startx); getmaxyx(win, height, width); box(win, 0, 0); mvwaddch(win, 2, 0, ACS_LTEE); mvwhline(win, 2, 1, ACS_HLINE, width - 2); mvwaddch(win, 2, width - 1, ACS_RTEE); print_in_middle(win, 1, 0, width, label, COLOR_PAIR(label_color)); } void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) { int length, x, y; float temp; if(win == NULL) win = stdscr; getyx(win, y, x); if(startx != 0) x = startx; if(starty != 0) y = starty; if(width == 0) width = 80; length = strlen(string); temp = (width - length)/ 2; x = startx + (int)temp; wattron(win, color); mvwprintw(win, y, x, "%s", string); wattroff(win, color); refresh(); }
1.16.4 사용자 포인터 쓰기 ¶
1.16.5 패널 이동 및 크기 변경 ¶
#include <panel.h> typedef struct _PANEL_DATA { int x, y, w, h; char label[80]; int label_color; PANEL *next; }PANEL_DATA; #define NLINES 10 #define NCOLS 40 void init_wins(WINDOW **wins, int n); void win_show(WINDOW *win, char *label, int label_color); void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color); void set_user_ptrs(PANEL **panels, int n); int main() { WINDOW *my_wins[3]; PANEL *my_panels[3]; PANEL_DATA *top; PANEL *stack_top; WINDOW *temp_win, *old_win; int ch; int newx, newy, neww, newh; int size = FALSE, move = FALSE; /* Initialize curses */ initscr(); start_color(); cbreak(); noecho(); keypad(stdscr, TRUE); /* Initialize all the colors */ init_pair(1, COLOR_RED, COLOR_BLACK); init_pair(2, COLOR_GREEN, COLOR_BLACK); init_pair(3, COLOR_BLUE, COLOR_BLACK); init_pair(4, COLOR_CYAN, COLOR_BLACK); init_wins(my_wins, 3); /* Attach a panel to each window */ /* Order is bottom up */ my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */ my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */ my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */ set_user_ptrs(my_panels, 3); /* Update the stacking order. 2nd panel will be on top */ update_panels(); /* Show it on the screen */ attron(COLOR_PAIR(4)); mvprintw(LINES - 3, 0, "Use 'm' for moving, 'r' for resizing"); mvprintw(LINES - 2, 0, "Use tab to browse through the windows (F1 to Exit)"); attroff(COLOR_PAIR(4)); doupdate(); stack_top = my_panels[2]; top = (PANEL_DATA *)panel_userptr(stack_top); newx = top->x; newy = top->y; neww = top->w; newh = top->h; while((ch = getch()) != KEY_F(1)) { switch(ch) { case 9: /* Tab */ top = (PANEL_DATA *)panel_userptr(stack_top); top_panel(top->next); stack_top = top->next; top = (PANEL_DATA *)panel_userptr(stack_top); newx = top->x; newy = top->y; neww = top->w; newh = top->h; break; case 'r': /* Re-Size*/ size = TRUE; attron(COLOR_PAIR(4)); mvprintw(LINES - 4, 0, "Entered Resizing :Use Arrow Keys to resize and press <ENTER> to end resizing"); refresh(); attroff(COLOR_PAIR(4)); break; case 'm': /* Move */ attron(COLOR_PAIR(4)); mvprintw(LINES - 4, 0, "Entered Moving: Use Arrow Keys to Move and press <ENTER> to end moving"); refresh(); attroff(COLOR_PAIR(4)); move = TRUE; break; case KEY_LEFT: if(size == TRUE) { --newx; ++neww; } if(move == TRUE) --newx; break; case KEY_RIGHT: if(size == TRUE) { ++newx; --neww; } if(move == TRUE) ++newx; break; case KEY_UP: if(size == TRUE) { --newy; ++newh; } if(move == TRUE) --newy; break; case KEY_DOWN: if(size == TRUE) { ++newy; --newh; } if(move == TRUE) ++newy; break; case 10: /* Enter */ move(LINES - 4, 0); clrtoeol(); refresh(); if(size == TRUE) { old_win = panel_window(stack_top); temp_win = newwin(newh, neww, newy, newx); replace_panel(stack_top, temp_win); win_show(temp_win, top->label, top->label_color); delwin(old_win); size = FALSE; } if(move == TRUE) { move_panel(stack_top, newy, newx); move = FALSE; } break; } attron(COLOR_PAIR(4)); mvprintw(LINES - 3, 0, "Use 'm' for moving, 'r' for resizing"); mvprintw(LINES - 2, 0, "Use tab to browse through the windows (F1 to Exit)"); attroff(COLOR_PAIR(4)); refresh(); update_panels(); doupdate(); } endwin(); return 0; } /* Put all the windows */ void init_wins(WINDOW **wins, int n) { int x, y, i; char label[80]; y = 2; x = 10; for(i = 0; i < n; ++i) { wins[i] = newwin(NLINES, NCOLS, y, x); sprintf(label, "Window Number %d", i + 1); win_show(wins[i], label, i + 1); y += 3; x += 7; } } /* Set the PANEL_DATA structures for individual panels */ void set_user_ptrs(PANEL **panels, int n) { PANEL_DATA *ptrs; WINDOW *win; int x, y, w, h, i; char temp[80]; ptrs = (PANEL_DATA *)calloc(n, sizeof(PANEL_DATA)); for(i = 0;i < n; ++i) { win = panel_window(panels[i]); getbegyx(win, y, x); getmaxyx(win, h, w); ptrs[i].x = x; ptrs[i].y = y; ptrs[i].w = w; ptrs[i].h = h; sprintf(temp, "Window Number %d", i + 1); strcpy(ptrs[i].label, temp); ptrs[i].label_color = i + 1; if(i + 1 == n) ptrs[i].next = panels[0]; else ptrs[i].next = panels[i + 1]; set_panel_userptr(panels[i], &ptrs[i]); } } /* Show the window with a border and a label */ void win_show(WINDOW *win, char *label, int label_color) { int startx, starty, height, width; getbegyx(win, starty, startx); getmaxyx(win, height, width); box(win, 0, 0); mvwaddch(win, 2, 0, ACS_LTEE); mvwhline(win, 2, 1, ACS_HLINE, width - 2); mvwaddch(win, 2, width - 1, ACS_RTEE); print_in_middle(win, 1, 0, width, label, COLOR_PAIR(label_color)); } void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) { int length, x, y; float temp; if(win == NULL) win = stdscr; getyx(win, y, x); if(startx != 0) x = startx; if(starty != 0) y = starty; if(width == 0) width = 80; length = strlen(string); temp = (width - length)/ 2; x = startx + (int)temp; wattron(win, color); mvwprintw(win, y, x, "%s", string); wattroff(win, color); refresh(); }
1.16.6 패널 숨기기 및 보여주기 ¶
#include <panel.h> typedef struct _PANEL_DATA { int hide; /* TRUE if panel is hidden */ }PANEL_DATA; #define NLINES 10 #define NCOLS 40 void init_wins(WINDOW **wins, int n); void win_show(WINDOW *win, char *label, int label_color); void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color); int main() { WINDOW *my_wins[3]; PANEL *my_panels[3]; PANEL_DATA panel_datas[3]; PANEL_DATA *temp; int ch; /* Initialize curses */ initscr(); start_color(); cbreak(); noecho(); keypad(stdscr, TRUE); /* Initialize all the colors */ init_pair(1, COLOR_RED, COLOR_BLACK); init_pair(2, COLOR_GREEN, COLOR_BLACK); init_pair(3, COLOR_BLUE, COLOR_BLACK); init_pair(4, COLOR_CYAN, COLOR_BLACK); init_wins(my_wins, 3); /* Attach a panel to each window */ /* Order is bottom up */ my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */ my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */ my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */ /* Initialize panel datas saying that nothing is hidden */ panel_datas[0].hide = FALSE; panel_datas[1].hide = FALSE; panel_datas[2].hide = FALSE; set_panel_userptr(my_panels[0], &panel_datas[0]); set_panel_userptr(my_panels[1], &panel_datas[1]); set_panel_userptr(my_panels[2], &panel_datas[2]); /* Update the stacking order. 2nd panel will be on top */ update_panels(); /* Show it on the screen */ attron(COLOR_PAIR(4)); mvprintw(LINES - 3, 0, "Show or Hide a window with 'a'(first window) 'b'(Second Window) 'c'(Third Window)"); mvprintw(LINES - 2, 0, "F1 to Exit"); attroff(COLOR_PAIR(4)); doupdate(); while((ch = getch()) != KEY_F(1)) { switch(ch) { case 'a': temp = (PANEL_DATA *)panel_userptr(my_panels[0]); if(temp->hide == FALSE) { hide_panel(my_panels[0]); temp->hide = TRUE; } else { show_panel(my_panels[0]); temp->hide = FALSE; } break; case 'b': temp = (PANEL_DATA *)panel_userptr(my_panels[1]); if(temp->hide == FALSE) { hide_panel(my_panels[1]); temp->hide = TRUE; } else { show_panel(my_panels[1]); temp->hide = FALSE; } break; case 'c': temp = (PANEL_DATA *)panel_userptr(my_panels[2]); if(temp->hide == FALSE) { hide_panel(my_panels[2]); temp->hide = TRUE; } else { show_panel(my_panels[2]); temp->hide = FALSE; } break; } update_panels(); doupdate(); } endwin(); return 0; } /* Put all the windows */ void init_wins(WINDOW **wins, int n) { int x, y, i; char label[80]; y = 2; x = 10; for(i = 0; i < n; ++i) { wins[i] = newwin(NLINES, NCOLS, y, x); sprintf(label, "Window Number %d", i + 1); win_show(wins[i], label, i + 1); y += 3; x += 7; } } /* Show the window with a border and a label */ void win_show(WINDOW *win, char *label, int label_color) { int startx, starty, height, width; getbegyx(win, starty, startx); getmaxyx(win, height, width); box(win, 0, 0); mvwaddch(win, 2, 0, ACS_LTEE); mvwhline(win, 2, 1, ACS_HLINE, width - 2); mvwaddch(win, 2, width - 1, ACS_RTEE); print_in_middle(win, 1, 0, width, label, COLOR_PAIR(label_color)); } void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) { int length, x, y; float temp; if(win == NULL) win = stdscr; getyx(win, y, x); if(startx != 0) x = startx; if(starty != 0) y = starty; if(width == 0) width = 80; length = strlen(string); temp = (width - length)/ 2; x = startx + (int)temp; wattron(win, color); mvwprintw(win, y, x, "%s", string); wattroff(win, color); refresh(); }
1.16.7 panel_above() 와 panel_below() 함수들 ¶
1.17 메뉴 라이브러리 ¶
1.17.1 개괄 ¶
- curses 를 초기화 한다.
- new_item() 을 써서 아이템을 생성한다. 각 아이템에 대해 이름과 설명을 명시할 수도 있다.
- new_menu() 에 결합될 아이템을 명시해서 메뉴를 만든다.
- menu_post() 함수로 메뉴를 붙이고 화면을 리프레쉬 한다.
- 루프를 돌며 사용자 요청을 처리하고 menu_driver 를 통해 메뉴에 필요한 갱신을 한다.
- menu_unpost() 함수로 메뉴를 떼어낸다.
- free_menu() 로 메뉴에 할당된 메모리를 해제한다.
- free_item() 으로 아이템에 할당된 메모리를 해제한다.
- curses 를 종료한다.
1.17.2 메뉴 라이브러리와 컴파일 하기 ¶
#! #include <menu.h> . . . compile and link: gcc <program file> -lmenu -lncurses
#include <curses.h> #include <menu.h> #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define CTRLD 4 char *choices[] = { "Choice 1", "Choice 2", "Choice 3", "Choice 4", "Exit", }; int main() { ITEM **my_items; int c; MENU *my_menu; int n_choices, i; ITEM *cur_item; initscr(); cbreak(); noecho(); keypad(stdscr, TRUE); n_choices = ARRAY_SIZE(choices); my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *)); for(i = 0; i < n_choices; ++i) my_items[i] = new_item(choices[i], choices[i]); my_items[n_choices] = (ITEM *)NULL; my_menu = new_menu((ITEM **)my_items); mvprintw(LINES - 2, 0, "F1 to Exit"); post_menu(my_menu); refresh(); while((c = getch()) != KEY_F(1)) { switch(c) { case KEY_DOWN: menu_driver(my_menu, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(my_menu, REQ_UP_ITEM); break; } } free_item(my_items[0]); free_item(my_items[1]); free_menu(my_menu); endwin(); }
#! REQ_LEFT_ITEM Move left to an item. REQ_RIGHT_ITEM Move right to an item. REQ_UP_ITEM Move up to an item. REQ_DOWN_ITEM Move down to an item. REQ_SCR_ULINE Scroll up a line. REQ_SCR_DLINE Scroll down a line. REQ_SCR_DPAGE Scroll down a page. REQ_SCR_UPAGE Scroll up a page. REQ_FIRST_ITEM Move to the first item. REQ_LAST_ITEM Move to the last item. REQ_NEXT_ITEM Move to the next item. REQ_PREV_ITEM Move to the previous item. REQ_TOGGLE_ITEM Select/deselect an item. REQ_CLEAR_PATTERN Clear the menu pattern buffer. REQ_BACK_PATTERN Delete the previous character from the pattern buffer. REQ_NEXT_MATCH Move to the next item matching the pattern match. REQ_PREV_MATCH Move to the previous item matching the pattern match.
1.17.3 Menu Driver: 메뉴 시스템의 큰 일꾼 ¶
- REQ_LEFT_ITEM and REQ_RIGHT_ITEM
- REQ_UP_ITEM and REQ_DOWN_ITEM
- REQ_SCR_* options
- REQ_FIRST_ITEM, REQ_LAST_ITEM, REQ_NEXT_ITEM and REQ_PREV_ITEM
- REQ_TOGGLE_ITEM
- Pattern Requests
- Mouse Requests
1.17.4 메뉴 윈도우 ¶
#include <menu.h> #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define CTRLD 4 char *choices[] = { "Choice 1", "Choice 2", "Choice 3", "Choice 4", "Exit", (char *)NULL, }; void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color); int main() { ITEM **my_items; int c; MENU *my_menu; WINDOW *my_menu_win; int n_choices, i; /* Initialize curses */ initscr(); start_color(); cbreak(); noecho(); keypad(stdscr, TRUE); init_pair(1, COLOR_RED, COLOR_BLACK); /* Create items */ n_choices = ARRAY_SIZE(choices); my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *)); for(i = 0; i < n_choices; ++i) my_items[i] = new_item(choices[i], choices[i]); /* Crate menu */ my_menu = new_menu((ITEM **)my_items); /* Create the window to be associated with the menu */ my_menu_win = newwin(10, 40, 4, 4); keypad(my_menu_win, TRUE); /* Set main window and sub window */ set_menu_win(my_menu, my_menu_win); set_menu_sub(my_menu, derwin(my_menu_win, 6, 38, 3, 1)); /* Set menu mark to the string " * " */ set_menu_mark(my_menu, " * "); /* Print a border around the main window and print a title */ box(my_menu_win, 0, 0); print_in_middle(my_menu_win, 1, 0, 40, "My Menu", COLOR_PAIR(1)); mvwaddch(my_menu_win, 2, 0, ACS_LTEE); mvwhline(my_menu_win, 2, 1, ACS_HLINE, 38); mvwaddch(my_menu_win, 2, 39, ACS_RTEE); mvprintw(LINES - 2, 0, "F1 to exit"); refresh(); /* Post the menu */ post_menu(my_menu); wrefresh(my_menu_win); while((c = wgetch(my_menu_win)) != KEY_F(1)) { switch(c) { case KEY_DOWN: menu_driver(my_menu, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(my_menu, REQ_UP_ITEM); break; } wrefresh(my_menu_win); } /* Unpost and free all the memory taken up */ unpost_menu(my_menu); free_menu(my_menu); for(i = 0; i < n_choices; ++i) free_item(my_items[i]); endwin(); } void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) { int length, x, y; float temp; if(win == NULL) win = stdscr; getyx(win, y, x); if(startx != 0) x = startx; if(starty != 0) y = starty; if(width == 0) width = 80; length = strlen(string); temp = (width - length)/ 2; x = startx + (int)temp; wattron(win, color); mvwprintw(win, y, x, "%s", string); wattroff(win, color); refresh(); }
1.17.5 메뉴 스크롤 하기 ¶
#include <curses.h> #include <menu.h> #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define CTRLD 4 char *choices[] = { "Choice 1", "Choice 2", "Choice 3", "Choice 4", "Choice 5", "Choice 6", "Choice 7", "Choice 8", "Choice 9", "Choice 10", "Exit", (char *)NULL, }; void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color); int main() { ITEM **my_items; int c; MENU *my_menu; WINDOW *my_menu_win; int n_choices, i; /* Initialize curses */ initscr(); start_color(); cbreak(); noecho(); keypad(stdscr, TRUE); init_pair(1, COLOR_RED, COLOR_BLACK); init_pair(2, COLOR_CYAN, COLOR_BLACK); /* Create items */ n_choices = ARRAY_SIZE(choices); my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *)); for(i = 0; i < n_choices; ++i) my_items[i] = new_item(choices[i], choices[i]); /* Crate menu */ my_menu = new_menu((ITEM **)my_items); /* Create the window to be associated with the menu */ my_menu_win = newwin(10, 40, 4, 4); keypad(my_menu_win, TRUE); /* Set main window and sub window */ set_menu_win(my_menu, my_menu_win); set_menu_sub(my_menu, derwin(my_menu_win, 6, 38, 3, 1)); set_menu_format(my_menu, 5, 1); /* Set menu mark to the string " * " */ set_menu_mark(my_menu, " * "); /* Print a border around the main window and print a title */ box(my_menu_win, 0, 0); print_in_middle(my_menu_win, 1, 0, 40, "My Menu", COLOR_PAIR(1)); mvwaddch(my_menu_win, 2, 0, ACS_LTEE); mvwhline(my_menu_win, 2, 1, ACS_HLINE, 38); mvwaddch(my_menu_win, 2, 39, ACS_RTEE); /* Post the menu */ post_menu(my_menu); wrefresh(my_menu_win); attron(COLOR_PAIR(2)); mvprintw(LINES - 2, 0, "Use PageUp and PageDown to scoll down or up a page of items"); mvprintw(LINES - 1, 0, "Arrow Keys to navigate (F1 to Exit)"); attroff(COLOR_PAIR(2)); refresh(); while((c = wgetch(my_menu_win)) != KEY_F(1)) { switch(c) { case KEY_DOWN: menu_driver(my_menu, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(my_menu, REQ_UP_ITEM); break; case KEY_NPAGE: menu_driver(my_menu, REQ_SCR_DPAGE); break; case KEY_PPAGE: menu_driver(my_menu, REQ_SCR_UPAGE); break; } wrefresh(my_menu_win); } /* Unpost and free all the memory taken up */ unpost_menu(my_menu); free_menu(my_menu); for(i = 0; i < n_choices; ++i) free_item(my_items[i]); endwin(); } void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) { int length, x, y; float temp; if(win == NULL) win = stdscr; getyx(win, y, x); if(startx != 0) x = startx; if(starty != 0) y = starty; if(width == 0) width = 80; length = strlen(string); temp = (width - length)/ 2; x = startx + (int)temp; wattron(win, color); mvwprintw(win, y, x, "%s", string); wattroff(win, color); refresh(); }
1.17.6 여러 열을 가진 메뉴 ¶
#include <curses.h> #include <menu.h> #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define CTRLD 4 char *choices[] = { "Choice 1", "Choice 2", "Choice 3", "Choice 4", "Choice 5", "Choice 6", "Choice 7", "Choice 8", "Choice 9", "Choice 10", "Choice 11", "Choice 12", "Choice 13", "Choice 14", "Choice 15", "Choice 16", "Choice 17", "Choice 18", "Choice 19", "Choice 20", "Exit", (char *)NULL, }; int main() { ITEM **my_items; int c; MENU *my_menu; WINDOW *my_menu_win; int n_choices, i; /* Initialize curses */ initscr(); start_color(); cbreak(); noecho(); keypad(stdscr, TRUE); init_pair(1, COLOR_RED, COLOR_BLACK); init_pair(2, COLOR_CYAN, COLOR_BLACK); /* Create items */ n_choices = ARRAY_SIZE(choices); my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *)); for(i = 0; i < n_choices; ++i) my_items[i] = new_item(choices[i], choices[i]); /* Crate menu */ my_menu = new_menu((ITEM **)my_items); /* Set menu option not to show the description */ menu_opts_off(my_menu, O_SHOWDESC); /* Create the window to be associated with the menu */ my_menu_win = newwin(10, 70, 4, 4); keypad(my_menu_win, TRUE); /* Set main window and sub window */ set_menu_win(my_menu, my_menu_win); set_menu_sub(my_menu, derwin(my_menu_win, 6, 68, 3, 1)); set_menu_format(my_menu, 5, 3); set_menu_mark(my_menu, " * "); /* Print a border around the main window and print a title */ box(my_menu_win, 0, 0); attron(COLOR_PAIR(2)); mvprintw(LINES - 3, 0, "Use PageUp and PageDown to scroll"); mvprintw(LINES - 2, 0, "Use Arrow Keys to navigate (F1 to Exit)"); attroff(COLOR_PAIR(2)); refresh(); /* Post the menu */ post_menu(my_menu); wrefresh(my_menu_win); while((c = wgetch(my_menu_win)) != KEY_F(1)) { switch(c) { case KEY_DOWN: menu_driver(my_menu, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(my_menu, REQ_UP_ITEM); break; case KEY_LEFT: menu_driver(my_menu, REQ_LEFT_ITEM); break; case KEY_RIGHT: menu_driver(my_menu, REQ_RIGHT_ITEM); break; case KEY_NPAGE: menu_driver(my_menu, REQ_SCR_DPAGE); break; case KEY_PPAGE: menu_driver(my_menu, REQ_SCR_UPAGE); break; } wrefresh(my_menu_win); } /* Unpost and free all the memory taken up */ unpost_menu(my_menu); free_menu(my_menu); for(i = 0; i < n_choices; ++i) free_item(my_items[i]); endwin(); }
#! O_ONEVALUE Only one item can be selected for this menu. O_SHOWDESC Display the item descriptions when the menu is posted. O_ROWMAJOR Display the menu in row-major order. O_IGNORECASE Ignore the case when pattern-matching. O_SHOWMATCH Move the cursor to within the item name while pat tern-matching. O_NONCYCLIC Don't wrap around next-item and previous-item, requests to the other end of the menu.
1.17.7 여러 값을 가진 메뉴 ¶
#include <curses.h> #include <menu.h> #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define CTRLD 4 char *choices[] = { "Choice 1", "Choice 2", "Choice 3", "Choice 4", "Choice 5", "Choice 6", "Choice 7", "Exit", }; int main() { ITEM **my_items; int c; MENU *my_menu; int n_choices, i; ITEM *cur_item; /* Initialize curses */ initscr(); cbreak(); noecho(); keypad(stdscr, TRUE); /* Initialize items */ n_choices = ARRAY_SIZE(choices); my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *)); for(i = 0; i < n_choices; ++i) my_items[i] = new_item(choices[i], choices[i]); my_items[n_choices] = (ITEM *)NULL; my_menu = new_menu((ITEM **)my_items); /* Make the menu multi valued */ menu_opts_off(my_menu, O_ONEVALUE); mvprintw(LINES - 3, 0, "Use <SPACE> to select or unselect an item."); mvprintw(LINES - 2, 0, "<ENTER> to see presently selected items(F1 to Exit)"); post_menu(my_menu); refresh(); while((c = getch()) != KEY_F(1)) { switch(c) { case KEY_DOWN: menu_driver(my_menu, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(my_menu, REQ_UP_ITEM); break; case ' ': menu_driver(my_menu, REQ_TOGGLE_ITEM); break; case 10: /* Enter */ { char temp[200]; ITEM **items; items = menu_items(my_menu); temp[0] = '\0'; for(i = 0; i < item_count(my_menu); ++i) if(item_value(items[i]) == TRUE) { strcat(temp, item_name(items[i])); strcat(temp, " "); } move(20, 0); clrtoeol(); mvprintw(20, 0, temp); refresh(); } break; } } free_item(my_items[0]); free_item(my_items[1]); free_menu(my_menu); endwin(); }
1.17.8 메뉴 옵션들 ¶
#include <menu.h> #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define CTRLD 4 char *choices[] = { "Choice 1", "Choice 2", "Choice 3", "Choice 4", "Choice 5", "Choice 6", "Choice 7", "Exit", }; int main() { ITEM **my_items; int c; MENU *my_menu; int n_choices, i; ITEM *cur_item; /* Initialize curses */ initscr(); start_color(); cbreak(); noecho(); keypad(stdscr, TRUE); init_pair(1, COLOR_RED, COLOR_BLACK); init_pair(2, COLOR_GREEN, COLOR_BLACK); init_pair(3, COLOR_MAGENTA, COLOR_BLACK); /* Initialize items */ n_choices = ARRAY_SIZE(choices); my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *)); for(i = 0; i < n_choices; ++i) my_items[i] = new_item(choices[i], choices[i]); my_items[n_choices] = (ITEM *)NULL; item_opts_off(my_items[3], O_SELECTABLE); item_opts_off(my_items[6], O_SELECTABLE); /* Create menu */ my_menu = new_menu((ITEM **)my_items); /* Set fore ground and back ground of the menu */ set_menu_fore(my_menu, COLOR_PAIR(1) | A_REVERSE); set_menu_back(my_menu, COLOR_PAIR(2)); set_menu_grey(my_menu, COLOR_PAIR(3)); /* Post the menu */ mvprintw(LINES - 3, 0, "Press <ENTER> to see the option selected"); mvprintw(LINES - 2, 0, "Up and Down arrow keys to naviage (F1 to Exit)"); post_menu(my_menu); refresh(); while((c = getch()) != KEY_F(1)) { switch(c) { case KEY_DOWN: menu_driver(my_menu, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(my_menu, REQ_UP_ITEM); break; case 10: /* Enter */ move(20, 0); clrtoeol(); mvprintw(20, 0, "Item selected is : %s", item_name(current_item(my_menu))); pos_menu_cursor(my_menu); break; } } unpost_menu(my_menu); for(i = 0; i < n_choices; ++i) free_item(my_items[i]); free_menu(my_menu); endwin(); }
1.17.9 유용한 사용자 포인터 ¶
#include <curses.h> #include <menu.h> #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define CTRLD 4 char *choices[] = { "Choice 1", "Choice 2", "Choice 3", "Choice 4", "Choice 5", "Choice 6", "Choice 7", "Exit", }; void func(char *name); int main() { ITEM **my_items; int c; MENU *my_menu; int n_choices, i; ITEM *cur_item; /* Initialize curses */ initscr(); start_color(); cbreak(); noecho(); keypad(stdscr, TRUE); init_pair(1, COLOR_RED, COLOR_BLACK); init_pair(2, COLOR_GREEN, COLOR_BLACK); init_pair(3, COLOR_MAGENTA, COLOR_BLACK); /* Initialize items */ n_choices = ARRAY_SIZE(choices); my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *)); for(i = 0; i < n_choices; ++i) { my_items[i] = new_item(choices[i], choices[i]); /* Set the user pointer */ set_item_userptr(my_items[i], func); } my_items[n_choices] = (ITEM *)NULL; /* Create menu */ my_menu = new_menu((ITEM **)my_items); /* Post the menu */ mvprintw(LINES - 3, 0, "Press <ENTER> to see the option selected"); mvprintw(LINES - 2, 0, "Up and Down arrow keys to naviage (F1 to Exit)"); post_menu(my_menu); refresh(); while((c = getch()) != KEY_F(1)) { switch(c) { case KEY_DOWN: menu_driver(my_menu, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(my_menu, REQ_UP_ITEM); break; case 10: /* Enter */ { ITEM *cur; void (*p)(char *); cur = current_item(my_menu); p = item_userptr(cur); p((char *)item_name(cur)); pos_menu_cursor(my_menu); break; } break; } } unpost_menu(my_menu); for(i = 0; i < n_choices; ++i) free_item(my_items[i]); free_menu(my_menu); endwin(); } void func(char *name) { move(20, 0); clrtoeol(); mvprintw(20, 0, "Item selected is : %s", name); }
1.18 폼 라이브러리 ¶
1.18.1 개괄 ¶
- curses 를 초기화 한다.
- new_field() 를 써서 필드를 생성한다. 필드의 넓이 와 높이 및 폼에서의 위치를 명시할 수 있다.
- new_form() 에 붙여넣을 필드를 명시해서 폼을 생성한다.
- form_post() 로 폼을 전달하고 화면을 리프레쉬한다.
- 루프를 돌며 사용자 요청을 처리하고 form_driver 로 form 에 필요한 갱신등을 한다.
- form_unpost() 폼을 떼어낸다.
- free_form() 함수로 폼에 할당된 메모리를 해제한다.
- free_field() 함수로 아이템에 할당된 메모리를 해제한다.
- curses 를 종료한다.
1.18.2 폼 라이브러리와 컴파일 하기 ¶
#! #include <form.h> . . . compile and link: gcc <program file> -lform -lncurses
#include <form.h> int main() { FIELD *field[3]; FORM *my_form; int ch; /* Initialize curses */ initscr(); cbreak(); noecho(); keypad(stdscr, TRUE); /* Initialize the fields */ field[0] = new_field(1, 10, 4, 18, 0, 0); field[1] = new_field(1, 10, 6, 18, 0, 0); field[2] = NULL; /* Set field options */ set_field_back(field[0], A_UNDERLINE); /* Print a line for the option */ field_opts_off(field[0], O_AUTOSKIP); /* Don't go to next field when this */ /* Field is filled up */ set_field_back(field[1], A_UNDERLINE); field_opts_off(field[1], O_AUTOSKIP); /* Create the form and post it */ my_form = new_form(field); post_form(my_form); refresh(); mvprintw(4, 10, "Value 1:"); mvprintw(6, 10, "Value 2:"); refresh(); /* Loop through to get user requests */ while((ch = getch()) != KEY_F(1)) { switch(ch) { case KEY_DOWN: /* Go to next field */ form_driver(my_form, REQ_NEXT_FIELD); /* Go to the end of the present buffer */ /* Leaves nicely at the last character */ form_driver(my_form, REQ_END_LINE); break; case KEY_UP: /* Go to previous field */ form_driver(my_form, REQ_PREV_FIELD); form_driver(my_form, REQ_END_LINE); break; default: /* If this is a normal character, it gets */ /* Printed */ form_driver(my_form, ch); break; } } /* Un post form and free the memory */ unpost_form(my_form); free_form(my_form); free_field(field[0]); free_field(field[1]); endwin(); return 0; }
1.18.3.1 필드의 위치와 크기 가져오기 ¶
int field_info( FIELD *field, /* field from which to fetch */ int *height, *int width, /* field size */ int *top, int *left, /* upper left corner */ int *offscreen, /* number of offscreen rows */ int *nbuf); /* number of working buffers */
1.18.3.2 필드 이동하기 ¶
int move_field( FIELD *field, /* field to alter */ int top, int left); /* new upper-left corner */
1.18.3.3 필드 정렬 ¶
int set_field_just(FIELD *field, /* field to alter */ int justmode); /* mode to set */ int field_just(FIELD *field); /* fetch justify mode of field */
1.18.3.4 필드 표현 속성 ¶
int set_field_fore(FIELD *field, /* field to alter */ chtype attr); /* attribute to set */ chtype field_fore(FIELD *field); /* field to query */ /* returns foreground attribute */ int set_field_back(FIELD *field, /* field to alter */ chtype attr); /* attribute to set */ chtype field_back(FIELD *field); /* field to query */ /* returns background attribute */ int set_field_pad(FIELD *field, /* field to alter */ int pad); /* pad character to set */ chtype field_pad(FIELD *field); /* field to query */ /* returns present pad character */
#include <form.h> int main() { FIELD *field[3]; FORM *my_form; int ch; /* Initialize curses */ initscr(); start_color(); cbreak(); noecho(); keypad(stdscr, TRUE); /* Initialize few color pairs */ init_pair(1, COLOR_WHITE, COLOR_BLUE); init_pair(2, COLOR_WHITE, COLOR_BLUE); /* Initialize the fields */ field[0] = new_field(1, 10, 4, 18, 0, 0); field[1] = new_field(1, 10, 6, 18, 0, 0); field[2] = NULL; /* Set field options */ set_field_fore(field[0], COLOR_PAIR(1));/* Put the field with blue background */ set_field_back(field[0], COLOR_PAIR(2));/* and white foreground (characters */ /* are printed in white */ field_opts_off(field[0], O_AUTOSKIP); /* Don't go to next field when this */ /* Field is filled up */ set_field_back(field[1], A_UNDERLINE); field_opts_off(field[1], O_AUTOSKIP); /* Create the form and post it */ my_form = new_form(field); post_form(my_form); refresh(); set_current_field(my_form, field[0]); /* Set focus to the colored field */ mvprintw(4, 10, "Value 1:"); mvprintw(6, 10, "Value 2:"); mvprintw(LINES - 2, 0, "Use UP, DOWN arrow keys to switch between fields"); refresh(); /* Loop through to get user requests */ while((ch = getch()) != KEY_F(1)) { switch(ch) { case KEY_DOWN: /* Go to next field */ form_driver(my_form, REQ_NEXT_FIELD); /* Go to the end of the present buffer */ /* Leaves nicely at the last character */ form_driver(my_form, REQ_END_LINE); break; case KEY_UP: /* Go to previous field */ form_driver(my_form, REQ_PREV_FIELD); form_driver(my_form, REQ_END_LINE); break; default: /* If this is a normal character, it gets */ /* Printed */ form_driver(my_form, ch); break; } } /* Un post form and free the memory */ unpost_form(my_form); free_form(my_form); free_field(field[0]); free_field(field[1]); endwin(); return 0; }
1.18.3.5 필드 옵션 비트 ¶
int set_field_opts(FIELD *field, /* field to alter */ int attr); /* attribute to set */ int field_opts_on(FIELD *field, /* field to alter */ int attr); /* attributes to turn on */ int field_opts_off(FIELD *field, /* field to alter */ int attr); /* attributes to turn off */ int field_opts(FIELD *field); /* field to query */
#include <form.h> #define STARTX 15 #define STARTY 4 #define WIDTH 25 #define N_FIELDS 3 int main() { FIELD *field[N_FIELDS]; FORM *my_form; int ch, i; /* Initialize curses */ initscr(); cbreak(); noecho(); keypad(stdscr, TRUE); /* Initialize the fields */ for(i = 0; i < N_FIELDS - 1; ++i) field[i] = new_field(1, WIDTH, STARTY + i * 2, STARTX, 0, 0); field[N_FIELDS - 1] = NULL; /* Set field options */ set_field_back(field[1], A_UNDERLINE); /* Print a line for the option */ field_opts_off(field[0], O_ACTIVE); /* This field is a static label */ field_opts_off(field[1], O_PUBLIC); /* This filed is like a password field*/ field_opts_off(field[1], O_AUTOSKIP); /* To avoid entering the same field */ /* after last character is entered */ /* Create the form and post it */ my_form = new_form(field); post_form(my_form); refresh(); set_field_just(field[0], JUSTIFY_CENTER); /* Center Justification */ set_field_buffer(field[0], 0, "This is a static Field"); /* Initialize the field */ mvprintw(STARTY, STARTX - 10, "Field 1:"); mvprintw(STARTY + 2, STARTX - 10, "Field 2:"); refresh(); /* Loop through to get user requests */ while((ch = getch()) != KEY_F(1)) { switch(ch) { case KEY_DOWN: /* Go to next field */ form_driver(my_form, REQ_NEXT_FIELD); /* Go to the end of the present buffer */ /* Leaves nicely at the last character */ form_driver(my_form, REQ_END_LINE); break; case KEY_UP: /* Go to previous field */ form_driver(my_form, REQ_PREV_FIELD); form_driver(my_form, REQ_END_LINE); break; default: /* If this is a normal character, it gets */ /* Printed */ form_driver(my_form, ch); break; } } /* Un post form and free the memory */ unpost_form(my_form); free_form(my_form); free_field(field[0]); free_field(field[1]); endwin(); return 0; }
1.18.3.6 필드 상태 ¶
int set_field_status(FIELD *field, /* field to alter */ int status); /* status to set */ int field_status(FIELD *field); /* fetch status of field */
1.18.3.7 필드 사용자 포인터 ¶
int set_field_userptr(FIELD *field, char *userptr); /* the user pointer you wish to associate */ /* with the field */ char *field_userptr(FIELD *field); /* fetch user pointer of the field */
1.18.3.8 크기가 변하는 필드 ¶
field_opts_off(field_pointer, O_STATIC);
int set_max_field(FIELD *field, /* Field on which to operate */ int max_growth); /* maximum growth allowed for the field */
int dynamic_field_info( FIELD *field, /* Field on which to operate */ int *prows, /* number of rows will be filled in this */ int *pcols, /* number of columns will be filled in this*/ int *pmax) /* maximum allowable growth will be filled */ /* in this */
- O_AUTOSKIP 필드 옵션은 O_STATIC 옵션이 꺼져있고 필드가 커질 수 있는 최대길이가 명시되어 있지 않으면 무시될 것이다. 보통은 사용자가 필드의 마지막 문자위치까지 입력하게되면 O_AUTOSKIP 이 REQ_NEXT_FIELD 를 form driver 에 전달하게 된다. 최대 길이값이 없는 동적 필드에서는 마지막 문자위치란 것이 없다. 만약 최대 길이값이 명시된다면, O_AUTOSKIP 옵션은 필드가 최대길이에 도달하면 보통처럼 작동할 것이다.
- O_STATIC 옵션이 꺼져 있으면 필드 정렬이 무시될 것이다. 보통은 set_field_just 함수를 써서 한줄 필드의 내용을 JUSTIFY_LEFT, JUSTIFY_RIGHT, JUSTIFY_CENTER 할 수 있다. 동적으로 커지는 한줄 필드에서는, 정의에 따라 크기가 커지고 수평으로 스크롤 될 것이다. 그러므로 정렬할 데이터보다 더 많은 데이터를 포함하고 있게 된다. field_just 함수의 리턴 값은 바뀌지 않을 것이다.
- 만약 O_STATIC 필드 옵션이 꺼져있고 필드가 커질 수 있는 최대길이가 명시되어 있지 않으면, O_NL_OVERLOAD 폼 옵션에 상관없이 폼 드라이버는 REQ_NEW_LINE 에 대해 똑같이 작동할 것이다. 보통은 O_NL_OVERLOAD 폼 옵션이 켜져 있으면, 필드의 마지막 줄에서 호출된 REQ_NEW_LINE 값은 내부적으로 REQ_NEXT_FIELD 를 부르게 된다. 반면 만약 필드가 한계없이 커질 수 있다면, 마지막 줄이라는 것이 없다. 그러므로 REQ_NEW_LINE 는 내부적으로 REQ_NEXT_FIELD 를 호출할 일이 없게 된다. 만약 최대길이값이 명시되어 있고 O_NL_OVERLOAD 폼옵션이 켜져 있으면, REQ_NEW_LINE 는 필드가 최대길이까지 커졌고 사용자가 마지막줄에 있을 때 호출됐을 경우, 내부적으로 REQ_NEXT_FIELD 만을 발생시키게 된다.
- dup_field 라는 라이브러리 호출은 보통처럼 작동할 것이다; 그것은 필드를 복사한다. 현재 버퍼크기와 필드의 내용까지 모두 말이다. 커질 수 있는 최대길이가 명시되어 있다면 그것 또한 복사될 것이다.
- link_field 라이브러리 호출도 보통처럼 작동할 것이다; 그것은 모든 필드속성은 복사하고, 원래 필드의 버퍼는 공유할 것이다. 만약 O_STATIC 필드옵션이 필드가 공유하는 버퍼에 의해 결과적으로 값이 변경되었다면, 버퍼보다 더 큰 데이터를 입력할때 시스템이 어떻게 작동하는가는 현재 작업하는 필드의 옵션 설정에 달려있게 된다.
- field_info 라이브러리 호출도 보통처럼 작동할 것이다; nrow 변수에는 new_field 의 원래 호출때의 값을 가지고 있을 것이다. 위에서 언급했듯이, 현재의 버퍼 크기를 알아올려면 dynamic_field_info 함수를 사용해야만 한다.
1.18.4 폼 윈도우 ¶
#include <form.h> void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color); int main() { FIELD *field[3]; FORM *my_form; WINDOW *my_form_win; int ch, rows, cols; /* Initialize curses */ initscr(); start_color(); cbreak(); noecho(); keypad(stdscr, TRUE); /* Initialize few color pairs */ init_pair(1, COLOR_RED, COLOR_BLACK); /* Initialize the fields */ field[0] = new_field(1, 10, 6, 1, 0, 0); field[1] = new_field(1, 10, 8, 1, 0, 0); field[2] = NULL; /* Set field options */ set_field_back(field[0], A_UNDERLINE); field_opts_off(field[0], O_AUTOSKIP); /* Don't go to next field when this */ /* Field is filled up */ set_field_back(field[1], A_UNDERLINE); field_opts_off(field[1], O_AUTOSKIP); /* Create the form and post it */ my_form = new_form(field); /* Calculate the area required for the form */ scale_form(my_form, &rows, &cols); /* Create the window to be associated with the form */ my_form_win = newwin(rows + 4, cols + 4, 4, 4); keypad(my_form_win, TRUE); /* Set main window and sub window */ set_form_win(my_form, my_form_win); set_form_sub(my_form, derwin(my_form_win, rows, cols, 2, 2)); /* Print a border around the main window and print a title */ box(my_form_win, 0, 0); print_in_middle(my_form_win, 1, 0, cols + 4, "My Form", COLOR_PAIR(1)); post_form(my_form); wrefresh(my_form_win); mvprintw(LINES - 2, 0, "Use UP, DOWN arrow keys to switch between fields"); refresh(); /* Loop through to get user requests */ while((ch = wgetch(my_form_win)) != KEY_F(1)) { switch(ch) { case KEY_DOWN: /* Go to next field */ form_driver(my_form, REQ_NEXT_FIELD); /* Go to the end of the present buffer */ /* Leaves nicely at the last character */ form_driver(my_form, REQ_END_LINE); break; case KEY_UP: /* Go to previous field */ form_driver(my_form, REQ_PREV_FIELD); form_driver(my_form, REQ_END_LINE); break; default: /* If this is a normal character, it gets */ /* Printed */ form_driver(my_form, ch); break; } } /* Un post form and free the memory */ unpost_form(my_form); free_form(my_form); free_field(field[0]); free_field(field[1]); endwin(); return 0; } void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) { int length, x, y; float temp; if(win == NULL) win = stdscr; getyx(win, y, x); if(startx != 0) x = startx; if(starty != 0) y = starty; if(width == 0) width = 80; length = strlen(string); temp = (width - length)/ 2; x = startx + (int)temp; wattron(win, color); mvwprintw(win, y, x, "%s", string); wattroff(win, color); refresh(); }
1.18.5 필드 인증 ¶
int set_field_type(FIELD *field, /* field to alter */ FIELDTYPE *ftype, /* type to associate */ ...); /* additional arguments*/
FIELDTYPE *field_type(FIELD *field); /* field to query */
- 어플리케이션 프로그램에서 set_field_buffer 함수를 호출해서 필드의 값을 바꾼 경우
- 링크되어 있는 필드의 값들이 간접적으로 바뀐 경우 -- 그 필드가 링크되어 있는 원래 필드의 값을 바꿔서 변경된 경우
int set_field_type(FIELD *field, /* field to alter */ TYPE_ALPHA, /* type to associate */ int width); /* maximum width of field */
int set_field_type(FIELD *field, /* field to alter */ TYPE_ALNUM, /* type to associate */ int width); /* maximum width of field */
int set_field_type(FIELD *field, /* field to alter */ TYPE_ENUM, /* type to associate */ char **valuelist; /* list of possible values */ int checkcase; /* case-sensitive? */ int checkunique); /* must specify uniquely? */
int set_field_type(FIELD *field, /* field to alter */ TYPE_INTEGER, /* type to associate */ int padding, /* # places to zero-pad to */ int vmin, int vmax); /* valid range */
int set_field_type(FIELD *field, /* field to alter */ TYPE_NUMERIC, /* type to associate */ int padding, /* # places of precision */ int vmin, int vmax); /* valid range */
int set_field_type(FIELD *field, /* field to alter */ TYPE_REGEXP, /* type to associate */ char *regexp); /* expression to match */
1.18.6 폼 드라이버: 폼 시스템의 큰 일꾼 ¶
int form_driver(FORM *form, /* form on which to operate */ int request) /* form request code */
1.18.6.1 페이지 탐색 리퀘스트 ¶
int set_new_page(FIELD *field,/* Field at which page break to be set or unset */ bool new_page_flag); /* should be TRUE to put a break */
- REQ_NEXT_PAGE Move to the next form page.
- REQ_PREV_PAGE Move to the previous form page.
- REQ_FIRST_PAGE Move to the first form page.
- REQ_LAST_PAGE Move to the last form page.
1.18.6.2 필드간 탐색 리퀘스트 ¶
- REQ_NEXT_FIELD Move to next field.
- REQ_PREV_FIELD Move to previous field.
- REQ_FIRST_FIELD Move to the first field.
- REQ_LAST_FIELD Move to the last field.
- REQ_SNEXT_FIELD Move to sorted next field.
- REQ_SPREV_FIELD Move to sorted previous field.
- REQ_SFIRST_FIELD Move to the sorted first field.
- REQ_SLAST_FIELD Move to the sorted last field.
- REQ_LEFT_FIELD Move left to field.
- REQ_RIGHT_FIELD Move right to field.
- REQ_UP_FIELD Move up to field.
- REQ_DOWN_FIELD Move down to field.
1.18.6.3 필드 내 탐색 리퀘스트 ¶
- REQ_NEXT_CHAR Move to next character.
- REQ_PREV_CHAR Move to previous character.
- REQ_NEXT_LINE Move to next line.
- REQ_PREV_LINE Move to previous line.
- REQ_NEXT_WORD Move to next word.
- REQ_PREV_WORD Move to previous word.
- REQ_BEG_FIELD Move to beginning of field.
- REQ_END_FIELD Move to end of field.
- REQ_BEG_LINE Move to beginning of line.
- REQ_END_LINE Move to end of line.
- REQ_LEFT_CHAR Move left in field.
- REQ_RIGHT_CHAR Move right in field.
- REQ_UP_CHAR Move up in field.
- REQ_DOWN_CHAR Move down in field.
1.18.6.4 스크롤 리퀘스트 ¶
- REQ_SCR_FLINE Scroll vertically forward a line.
- REQ_SCR_BLINE Scroll vertically backward a line.
- REQ_SCR_FPAGE Scroll vertically forward a page.
- REQ_SCR_BPAGE Scroll vertically backward a page.
- REQ_SCR_FHPAGE Scroll vertically forward half a page.
- REQ_SCR_BHPAGE Scroll vertically backward half a page.
- REQ_SCR_FCHAR Scroll horizontally forward a character.
- REQ_SCR_BCHAR Scroll horizontally backward a character.
- REQ_SCR_HFLINE Scroll horizontally one field width forward.
- REQ_SCR_HBLINE Scroll horizontally one field width backward.
- REQ_SCR_HFHALF Scroll horizontally one half field width forward.
- REQ_SCR_HBHALF Scroll horizontally one half field width backward.
1.18.6.5 에디트 리퀘스트 ¶
- REQ_INS_MODE Set insertion mode.
- REQ_OVL_MODE Set overlay mode.
- REQ_NEW_LINE New line request (see below for explanation).
- REQ_INS_CHAR Insert space at character location.
- REQ_INS_LINE Insert blank line at character location.
- REQ_DEL_CHAR Delete character at cursor.
- REQ_DEL_PREV Delete previous word at cursor.
- REQ_DEL_LINE Delete line at cursor.
- REQ_DEL_WORD Delete word at cursor.
- REQ_CLR_EOL Clear to end of line.
- REQ_CLR_EOF Clear to end of field.
- REQ_CLEAR_FIELD Clear entire field.
1.18.6.6 Order Requests ¶
- REQ_NEXT_CHOICE 버퍼의 현재 값의 다음에 해당하는 값을 가져온다.
- REQ_PREV_CHOICE 버퍼의 현재 값의 이전에 해당하는 값을 가져온다.
1.18.6.7 어플리케이션 명령들 ¶
1.19 툴과 위젯 라이브러리들 ¶
1.19.1 CDK (Curses Development Kit) ¶
1.19.1.1 위젯 리스트 ¶
#! Widget Type Quick Description =========================================================================== Alphalist Allows a user to select from a list of words, with the ability to narrow the search list by typing in a few characters of the desired word. Buttonbox This creates a multiple button widget. Calendar Creates a little simple calendar widget. Dialog Prompts the user with a message, and the user can pick an answer from the buttons provided. Entry Allows the user to enter various types of information. File Selector A file selector built from Cdk base widgets. This example shows how to create more complicated widgets using the Cdk widget library. Graph Draws a graph. Histogram Draws a histogram. Item List Creates a pop up field which allows the user to select one of several choices in a small field. Very useful for things like days of the week or month names. Label Displays messages in a pop up box, or the label can be considered part of the screen. Marquee Displays a message in a scrolling marquee. Matrix Creates a complex matrix with lots of options. Menu Creates a pull-down menu interface. Multiple Line Entry A multiple line entry field. Very useful for long fields. (like a description field) Radio List Creates a radio button list. Scale Creates a numeric scale. Used for allowing a user to pick a numeric value and restrict them to a range of values. Scrolling List Creates a scrolling list/menu list. Scrolling Window Creates a scrolling log file viewer. Can add information into the window while its running. A good widget for displaying the progress of something. (akin to a console window) Selection List Creates a multiple option selection list. Slider Akin to the scale widget, this widget provides a visual slide bar to represent the numeric value. Template Creates a entry field with character sensitive positions. Used for pre-formatted fields like dates and phone numbers. Viewer This is a file/information viewer. Very useful when you need to display loads of information. ===========================================================================
1.19.1.2 몇몇 매력적인 기능들 ¶
1.19.2 다이얼로그 ¶
1.19.3 Perl Curses Modules CURSES::FORM and CURSES::WIDGETS ¶
1.20 Just For Fun !!! ¶
1.20.1 The Game of Life ¶
1.20.2 Magic Square ¶
1.20.3 Towers of Hanoi ¶
1.20.4 Queens Puzzle ¶
1.20.6 Typing Tutor ¶
8. 문자단위 그래픽스 (Character Cell Graphics)
이장은 화소(pixel)를 기본으로 하지않는, 문자를 기본으로 하는 화면 입력과 출력을 다룬다. 우리가 문자(character)를 말할 때, 문자는 문자집합(charset)에 따라 변화되는 화소(pixel)의 조합을 의미한다. 텍스트(text)가 화소(pixel) 그래픽보다 매우 빨리 처리되기 때문에 그래픽 카드(graphic card)는 이미 한개이상의 문자집합(charset)을 제공하고, 기본적으로 텍스트(charset) 모드에서 동작한다. 간단(무딘)하고 지겨운 텍스트 표시하는 것 이상으로 단말기를 다룰 수 있다. 리눅스 단말기(terminal), 특히 콘솔(console)이 제공하는 특별한 특징들을 어떻게 사용할 것인가에 대해 설명하고자 한다.
- printf, sprintf, fprintf, scanf, sscanf, fscaf
이러한 함수들을 가지고 (표준출력 standard output), (표준에러 standard error), 또는 FILE *stream (files, 예를 들면)와 같은 다름 스트림(stream)에 형태가 지정된(formatted) 문자열을 출력할 수 있다. Scanf(...)는 비슷한 방법으로 형태가 지정된(formatted) 입력을 제공한다. - termcap
단말기 능력 데이타베이스 (The TERMinal CAPabilites database)는 /etc/termcap 이라는 ASCII 파일에 들어있는 단말기 특징 개체(terminal description entries)들의 집합이다. 여기서 특수문자들을 어떻게 표시하는가, 어떻게 동작(delete,insert characters or line)들을 수행하는가 그리고 단말기를 어떻게 초기화 하는가에 대한 정보를 찾을 수 있다. 이 데이타베이스는, 예를들면, vi 에디터에 의해 사용된다. 단말기 능력(terminal capabilities) (termcap(3x))을 사용하고 읽을 수 있는 view 라이브러리 함수들이 있다. 이 데이타베이스를 가지고, 프로그램은 같은 코드를 가진 단말기에서 다양한 작업을 할 수 있다. termcap 데이타베이스와 라이브러리 함수들의 사용은 단말기에 대해 오직 하위 수준의 접근 (low level access)을 제공한다. 속성(attributes)과 색상(colors)과 매개변수화된(parameterized) 출력을 바꾸는 것은 프로그래머에 의해 수행되어야만 한다. - terminfo database
단말기 정보 데이타베이스(the TERMinal INFOrmation database)는 termcap database를 기초로 하고 단말기 능력(terminal capabilities)을 설명하고 있지만, termcap보다는 더높은 수준(higher level)이다. terminfo를 사용하여, 프로그램은 화면 속성(screen attributes), 펑션키(function keys)와 같은 특별한 키의 사용과 그외의 것들을 쉽게 바꿀 수 있다. 데이타베이스는 /usr/lib/terminfo/[A-z,0-9]*에서 찾을 수 있다. 모든 파일은 한 단말기를 설명한다. - curses
Terminfo는 프로그램안에서 단말기(terminal)를 다루기(handling) 위한 좋은 기초이다. (BSD-)CURSES 라이브러리는 단말기에 대해 상위 수준의 접근(high level access)을 가능하게 하며, terminfo database를 기초로 한다. curses는 화면상의 윈도우를 열고 조종할 수 있도록 하며, 입력과 출력 함수들의 완벽한 집합을 제공하고 150개 이상의 단말기에 대해 단말기의 독립적인 방식의 비디오 속성을 변경시킬 수 있다. curses 라이브러리는 /usr/lib/libcurses.a에서 찾을 수 있다. 이것은 curses의 BSD 버전이다. - ncurses
Ncurses는 한단계 향상된 것이다. 1.8.6 버전에서는 SYSVR4에서 정의된 AT&T curses와 호환 되어야만 하고 색상 조종(color manipulation), 출력을 위한 특별한 최적화(special optimization for output), 단말기 지정 최적화(terminal specific optimizations) 등과 같은 확장을 가져야만 한다. 이것은 SUN-OS, HP, Linux와 같은 많은 시스템들에서 테스트 되어 왔다. 다른 것들을 대신해서 ncurses를 사용할 것을 추천한다. SYSV 유닉스 시스템(SUN의 Solaris같은) 상에서는 nurses와 같은 기능을 갖는 curses 라이브러리가 존재해야 한다. (실제로 solaris curses는 마우스 지원과 보다 많은 기능을 가지고 있다.)
- 8.1 libc안의 I/O 함수 (I/O Function in libc)
- 8.2 Termcap 라이브러리 (The Termcap Library)
- 8.3 Ncurses - 소개 (Introduction)
- 8.4 초기화 (Initializing)
- 8.5 윈도우 (Windows)
- 8.6 출력 (Output)
- 8.7 입력 (Input)
- 8.8 선택사항 (Options)
- 8.9 윈도우와 줄 지우기 (Clear Window and Lines)
- 8.10 단말기 업데이트 (Updating the Trminal)
- 8.11 비디오 속성과 색상 (Video Attributes and Color)
- 8.12 커서와 윈도우 좌표 (Cursor and Window Coordinates)
- 8.13 스크롤 (Scrolling)
- 8.14 패드 (Pads)
- 8.15 소프트-라벨 (Soft-labels)
- 8.16 잡동사니 (Miscellaneous)
- 8.17 Low-level 접근 (Access)
- 8.18 화면 덤프 (Screen Dump)
- 8.19 Termcap Emulation
- 8.20 Terminfo 함수들(Functions)
- 8.21 디버그 함수 (Debug Function)
- 8.22 Terminfo 능력 (Capabilities)
- 8.23 [N]Curses 함수 개관 ([N]Curses Function Overview)
8.1 libc안의 I/O 함수 (I/O Function in libc)
8.1.1 형식화된 출력 (Formatted Output)
printf(...) 함수는 형식이 있는 출력을 제공하고 아규먼트의 변형을 허락한다.
- int fprintf(FILE *stream, const char *format, ...),
은 출력을 변형시키고 stream에 쓴다. format안에 정의된 형태(format)로 쓰여진다. 이 함수는 쓰여진 문자들의 갯수를 반환하거나 에러시는 음수값을 반환한다.format는 두 종류의 객체를 포함한다.
- 출력을 위한 정상적인 문자들과
- 아규먼트를 어떻게 변형시키고 형식화할 것인가의 정보
- Flags
- -
형식화된 아규먼트는 왼쪽 여백에 인쇄된다. (디폴트는 아규먼트 필드의 오른쪽 여백이다.) - +
모든 숫자가 부호를 가지고 인쇄된다. (예, +12, -2.32)
- -
- Blank
첫번째 문자가 부호를 가지고 있지 않으면, 공백이 삽입된다. - 0
숫자 변환을 위해 필드의 폭은 왼쪽 편이 0으로 채워진다. - #
아규먼트를 위한 변환에 따라 출력을 바꾼다.- o 에 대해, 첫번째 숫자는 0.
- x, X 에 대해, 0x 또는 0X가 아규먼트의 앞에 인쇄된다.
- e, E, f, F 에 대해, 출력은 소수점을 갖는다.
- g, G 에 대해, 아규먼트의 끝에 제로(zeroes)가 인쇄된다.
- 최소한의 필드 폭을 위한 수
변형된 아규먼트는 아규먼트 자체의 가장 최소한의 크기를 갖는 필드안에 인쇄된다. 이 수(number)를 가지고 필드의 폭을 더 크게 만들 수 있다. 형식화된 아규먼트가 더 작은 경우, 필드의 폭은 제로 또는 공백으로 채워진다. - 필드의 폭과 정확도를 나누기 위한 점.
- 정확도를 위한 수.
- int printf(const char *format, ...)
fprintf(stdout,...)와 같음 - int sprintf(char *s, const char *format, ...)
출력이 문자(character) 포인터인 s (끝에 \0를 갖는)에 쓰인다는 것을 제외하곤 printf(...)와 같음(Note: s를 위한 충분한 메모리를 할당해야한다.)
- vprintf(const char *format, va_list arg)
vfprintf(FILE *stream, const char *format, va_list arg)
vsprintf(char *s, const char *format, va_list arg)
오직 arg에 아규먼트 리스트가 지정된 것일뿐, 위의 함수들과 같음
8.1.2 형식화된 입력 (Formatted Input)
형식화된 출력을 위해 printf(...)를 사용하는 것처럼 형식화된 입력을 위해 scanf(...)를 사용할 수 있다.
- int fscanf(FILE *stream, const char *format, ...)
fscanf(...)는 stream으로 부터 읽어서 format에서 정의된 규칙에 따라 입력을 변환한다. 결과는 주어진 아규먼트 안에 위치하게 된다. (Note:아규먼트들은 포인터여야만 한다.) format안에 더이상의 변환 규칙이 없을 때까지 읽는다. fscanf(..)는 첫번째 변환이 파일의 끝에 도달했거나 에러가 발생했을 때 EOF를 반환한다. 그렇지 않으면, 변환된 아규먼트의 수를 반환한다.format은 입력 아규먼트를 어떻게 형식화할 것인가에 대한 규칙을 포함한다. 이것은 또한 포함한다.:
- 공백(spaces)이나 탭(tab)은 무시된다.
- (%를 제외한) 일반적인 문자. 문자들은 연관된 위치의 입력안에 있어야 한다.
- %, 부가적인 문자 *(이것은 fscanf(..)가 아규먼트를 지정하는 것을 허락한다), 부가적인 숫자, 부가적인 문자 h,l 또는 L (이것은 타겟의 길이이다) 과 변환 문자로 조합된 변환 규칙들
- int scanf(const char * format, ...)
fscanf(stdin,...)과 같음 - int sscanf(char *str, const char *format, ...)
scanf(...)와 같지만, 입력은 str로 부터 온다.
8.2 Termcap 라이브러리 (The Termcap Library)
- 8.2.1 소개 (Instruction)
- 8.2.2 단말기 내용 찾기 (Find a Terminal Description)
- 8.2.3 단말기 내용 살펴보기 (Look at a Terminal Description)
- 8.2.4 Termcap 능력들 (Termcap Capabilities)
8.2.1 소개 (Instruction)
termcap 라이브러리는 /etc/termcap/에서 찾을 수 있는 termcap database에 대한 API이다. 이 라이브러리 함수들은 다음의 동작을 허용한다.:
- 현재 단말기의 설명(description)을 얻는다 : tgetent(...)
- 정보를 위한 설명을 검색한다 : tgetnum(...), tgetflag(...), tgetstr(...)
- 단말기의 지정 형태안에 숫자 파라미터들을 암호화한다 : tparam(...), tgoto(...)
- 충전물을 계산하고 수행한다 : tputs(...)
termcap 라이브러리를 사용하는 프로그램은 .h를 포함(include)하고 연결(link)되어야만 한다.
Termcap 함수들은 단말기에 독립적인 루틴들이지만 프로그래머들에게 단말기에 대한 하위 수준의 접근을 가능하게 한다. 보다 높은 패키지를 위해서는, curses나 ncurses가 사용되어야만 한다.
8.2.2 단말기 내용 찾기 (Find a Terminal Description)
- int tgetent(void *buffer, const char *termtype)
리눅스 운영체제 시스템상에서 현재 단말기 이름은 환경변수 안에 포함된다. 그래서, termtype는 (3)의 호출의 결과이다.termcap의 GNU 버전을 사용할 때 버퍼를 위한 메모리의 할당은 없다. 이것은 리눅스 하에서 우리가 가정할 수 있는 것이다. 그렇지 않으면, 2048 바이트를 할당해야만 한다. (전에는 버퍼는 오직 1024 바이트만이 필요했었지만, 그 크기가 두배가 되었다.)
tgetent(...)는 성공시 1을 반환하고 데이타베이스가 발경되었지만 TERM을 위한 개체(entry)가 없을 때 0을 반환한다. 나머지 에러들은 다른 값들을 반환한다.
다음의 예제는 tgetent(...)를 어떻게 사용하는지 설명해야만 한다.:
디폴트로 termcap은 데이타베이스처럼 /etc/termcap/을 사용한다. 한예로, 환경변수 TERMCAP이 $HOME/mytermcap로 지정되어 있으면, 모든 함수들은 /etc/termcap을 대신하여 사용한다. TERMCAP안에 선행하는 슬래쉬(slash)가 없는 정의된 값은 단말기에 대한 이름처럼 사용된다.
8.2.3 단말기 내용 살펴보기 (Look at a Terminal Description)
정보의 모든 조각들은 능력(capability)이라 불리어 진다. 모든 능력(capability)은 두 글자 코드이고, 모든 두 글자 코드는 능력(capability)을 위한 값에 의해 다음과 같다. 가능한 타입들:
- 숫자(Numeric):예를 들어 co - 컬럼의 수
- 논리적 자료 또는 플래그(Boolean or Flag):예를 들어 hc - 하드카피 단말기(hardcopy terminal)
- 문자열(String):예를 들어 st - 탭 위치 지정
각각의 능력(capability)은 단일 값 타입과 연관되어있다. (co는 항상 숫자, hc는 항상 플래그 그리고 st는 항상 문자열) 값들에는 세게의 다른 타입이 있고 그것들에게 질문하기위한 세개의 함수가 있다. char *name은 능력(capability)를 위한 두 글자 코드이다.
- int tgetnum(char *name)
co와 같은 숫자(numeric) 능력(capability) 값(value)을 얻는다. tgetnum(...)는 능력을 사용가능하다면, 숫자값을 반환하고 그렇지 않으면 1을 반환한다. (Note:반환되는 값은 음수가 아니다.) - int tgetflag(char *name)
논리적(boolean) 자료 (또는 플래그(flag))인 능력 값을 얻는다. 플래그가 존재하면 1, 그렇지 않으면 0을 반환한다. - char *tgetstr(char *name, char **area)
문자열인 능력값을 얻는다. 문자열에 대한 포인터를 반환하고 존재하지 않으면 NULL을 반환한다. GNU 버전에서, 영역이 NULL이면, termcap은 스스로 메모리를 할당할 것이다. termcap은 결코 그 포인터를 다시 참조하지 않는다. 그러므로 프로그램을 떠나기 전에 name을 풀어주는 것을 잊지말아라. 우리가 포인터를 위해 얼마나 많은 공간이 필요한지를 모르기 때문에, termcap이 이러한 일을 하도록 하는 것이 더 좋다.
8.2.4 Termcap 능력들 (Termcap Capabilities)
Boolean Capabilities
5i 프린터가 화면에 echo를 하지 않는다. am 자동 줄 바꿈을 의미하는 자동 마진 bs Control-H(8 dec)는 backspace를 수행한다. bw 왼쪽 여백에 대한 backspace는 이전의 라인과 오른쪽 여백을 가린다. da 표시(display)가 화면 위로 유지된다. db 표시(display)가 화면 아래로 유지된다. eo 공백이 커서 위치의 모든 문자들을 지운다. es Escape sequences와 특수문자들은 상태줄(ststus line)에서 작업한다. gn 일반적인 장치 hc 이것은 hardcopy 단말기이다. HC 커서는 바닥줄에 있지 않을 때 보기 어렵다. hs 상태줄(status line)을 갖는다. hz Hazel tine bug, 단말기는 물결(tilde) 문자들을 인쇄할 수 없다. in 단말기는 흰색공백을 채우기위해 공백이 아닌 NULL을 삽입한다. km 단말기는 메타 키(meta key)를 갖는다. mi 커서의 움직임은 삽입 모드에서 동작한다. ms 커서의 움직임은 표준출력/밑줄 모드에서 동작한다. NP pad 문자는 없다. NR ti는 te로 바뀌지 않는다. nx padding 없이, XON/XOFF를 사용해야만 한다. os 단말기는 overstrike 할 수 있다. ul overstrike 될 수 없을 지라도 단말기는 밑줄 그어 진다. xb Beehive glitch, f1는 ESCAPE를 보낸다, f2는 ^C를 보낸다. xn Newline/wraparound glitch xo 단말기는 xon/xoff 프로토콜을 사용한다. xs 표준출력을 통한 텍스트는 표준출력으로 표시되어진다. xt Teleray glitch, destructive tabs and odd standout mode
Numeric Capabilities
String Capacilies
8.3 Ncurses - 소개 (Introduction)
다음 용어들은 이 장에서 사용될 것이다.:
- window - 화면의 부분 이미지를 포함하는 내부적 표현이다. WINDOW는 .h에 정의되어있다.
- screen - 전체 화면(좌측 상단에서 부터 우측 하단까지) 크기를 갖는 창(window)이고 화면들이다.
- terminal - 화면이 현재 무엇처럼 보이는지에 대한 정보를 가지고 있는 특별한 화면(screen)이다.
- variables - 다음의 변수들과 상수들은 in.h에 정의되어있다.
- WINDOW *cursor - 현재 화면(current screen)
- WINDOW *stdscr - 표준 화면(standard screen)
- int LINES - 단말기(terminal)상의 라인들
- int COLS - 단말기(terminal)상의 컬럼들
- bool TRUE - true flag, 1
- bool FALSE - false flag, 0
- int ERR - error flag, -1
- int OK - ok flag, 0
- functions - 함수안에서 아규먼트에 대한 묘사는 다음의 타입이 있다:
- win - WINDOW*
- bf - bool
- ch - chtype
- str - char*
- chstr - chatype*
- fmt - char*
- otherwise int
대개 ncurses 라이브러리를 사용하는 프로그램은 이처럼 보인다.:
.h를 포함하는(including) 것은 WINDOW와 함수원형(function prototype)와 같이 ncurses를 위한 변수들과 타입들을 정의한다. 자동적으로 .h,.h,.h,.h를 포함한다.
initscr()는 ncurses 자료 구조들을 초기화하고 적당한 terminfo 파일을 읽는데 사용된다. 메모리는 할당되어진다. 에러가 발생한다면, initscr는 ERR를 반환한다 그렇지않으면 포인터가 반환되어진다. 부가적으로, 화면은 지워지게 되고 초기화 되어질 것이다.
endwin()은 ncurses로 부터 할당된 모든 자원들을 청소하고 tty 모드에 initscr()을 호출하기 전 상태를 저장한다. initscr()은 curses로 부터 다른 어떤 함수이전에 호출되어져야 하고 endwin()는 프로그램을 끝내기 전에 호출되어져야 한다. 한 단말기 이상에 출력을 하고자 할 때는 initscr() 대신에 newterm(...)를 사용할 수 있다.
프로그램 컴파일하기:
플래그 안에 당신이 좋아하는 것을 포함할 수 있다(gcc(1)). ncurses.h를 위한 경로가 수정되었으면 다음 줄을 포함(include)하여야 한다.
그렇지 않으면, ncurses.h,nterm.h,termcap.h,unctrl.h은 찾을 수 없을 것이다. Linux에서 사용가능한 다른 플래그들:
2는 gcc에게 최적화(optimization)하라고 말한다, -ansi는 ansi에 일치하는 c-code용이다, -Wall는 모든 경고(warning)를 인쇄할 것이다, -m486는 인텔 486를 위한 최적화된 code를 사용할 것이다.(binary는 인텔 386상에서도 사용될 수 있다.).
ncurses 라이브러리는 /usr/lib에서 찾을 수 있다. ncurses 라이브러리는 세 버전이 있다.
- libncurses.a 표준 ncurses 라이브러리
- libdcurses.a 디버깅(debugging)을 위한 ncurses
- libpcurses.a profiling를 위한 ncurses (1.8.6 libpcurses.a 이래 더이상 존재하지 않는다 ?)
- libcurses.a 네번째 버전은 아니지만, 최초의(original) BSD curses이다. (내 슬랙웨어 2.1.0에서는 bsd 패키지이다).
화면(screen)을 위한 자료구조는 .h에 정의된 것처럼 윈도우즈(Windows)라 불리어 진다. 윈도우는 프로그래머가 단말기에 출력하는 것없이 조종할 수 있는 메모리 안에 있는 문자 배열과 같은 것이다. 디폴트 윈도우는 단말기의 크기이다. newwin(...)를 가지고 다른 윈도우를 만들 수 있다.
최상으로 물리적인 단말기를 업데이트하기 위해, ncurses는 선언된 또 다른 윈도우를 가지고 있다. 이것은 단말기가 실제로 어떻게 보여지는가의 이미지이고 단말기가 어떻게 보여져야만 하는가의 이미지이다. refresh()가 호출될 때 출력되어질 것이다. ncurses는 안에 있는 정보를 가지고 물리적인 단말기를 업데이트할 것이다. 라이브러리 함수들은 업데이트 프로세스를 위해 내부의 최적된 것을 사용할 것이므로 가장 최적의 방법으로 다른 윈도우들을 변화시키고 한번에 화면을 업데이트할 수 있다.
ncurses 함수들을 가지고 자료 구조체 window를 조종할 수 있다. w로 시작하는 함수들은 당신이 윈도우(window)를 지정하는 것을 허용하는 반면, 다른 것들은 일반적으로 작용한다. mv로 시작하는 함수들은 커서를 처음의 y,x 위치로 이동시킨다.
문자는 속성(attributes)에 대한 부가적인 정보를 저장하는 long unsigned int값인 chtype 타입을 갖는다.
ncurses는 데이타베이스를 사용한다. 일반적으로 데이타베이스는 /lib/terminfo에 위치하고 ncurses는 지역 단말기 정의를 거기서 찾는다. 원래의 terminfo를 변화시키지 않고 단말기에 대한 몇몇 다른 정의들을 테스트하기를 원한다면, 환경변수(environment variable)를 지정(set)하라. ncurses는 이 변수들을 체크하고 /usr/lib/terminfo/를 대신하여 거기에 저장된 정의들을 사용할 것이다.
현재 ncurses 버전은 1.8.6()이다.
이장의 끝에서 BSD-Curses,ncurses와 Sun-OS 5.4의 curses에 대한 개관(overview)이 담긴 표를 발견할 수 있다. 지정된 함수와 그것이 구현된 곳을 찾고자 할 경우에 참조하라.
8.4 초기화 (Initializing)
- WINDOW *initscr()
이것은 ncurses를 사용하는 프로그램으로 부터 일반적으로 호출되는 첫번째 함수이다. 몇몇 경우에 있어서 slk_init(int), filter(), ripoffline(...) 또는 initscr() 이전의 use_env(bf) 호출은 유용하다. 여러개의 단말기를 사용할 때 (또는 능력(capabilities)을 테스트하는 경우), initscr()을 대신하여 newterm(...) 를 사용할 수 있다.initscr()는 적당한 terminfo 파일을 읽고 ncurses 자료 구조를 초기화하고 메모리를 할당하고 단말기가 가지고 있는 값들을 지정(set)할 것이다. 이것은 포인터를 반환하거나 에러가 발생했을 때 ERR를 반환한다. 포인터를 초기화할 필요는 없다.
initscr()는 당신을 위해 이것을 할 것이다. 반환값이 ERR이면, 당신의 프로그램은 ncurses 함수가 작업할 수 없으므로 종료해야만 한다.
- SCREEN *newterm(char *type, FILE *outfd, FILE *infd)
다수의 단말기 출력을 위해 initscr()를 대신하여 ncurses를 가지고 접근하기 위해 각각의 단말기에 대해 newterm(...)를 호출한다. type은 $TERM안에 포함되어 있는 단말기의 이름(예:ansi, xterm, vt100)이고 outfd는 출력 포인터(output pointer)이고 infd는 입력을 위해 사용되는 포인터이다. newterm(...)에 의해 열려진 각 단말기에 대해 endwin()를 호출하라. - SCREEN *set_term(SCREEN *new)
set_term(SCREEN)를 가지고 현재의 단말기를 바꿀(switch) 수 있다. 모든 함수들은 set_term(SCREEN)에 의해 지정된 현재의 단말기에 작용할 것이다. - int endwin()
endwin()는 청소를 하고 initscr()를 호출하기 전의 상태로 단말기 모드를 저장하고 커서를 좌측하단으로 이동시킬 것이다. 프로그램을 종료하기 위해 endwin()을 호출하기 전에 열려진 모든 윈도우를 닫는 것을 잊지 말아라.endwin()후에 부가적으로 refresh()를 호출하는 것은 initscr()를 호출하기 전에 가지고 있는 상태로 단말기를 저장할 것이다(visual-mode). 그렇지 않으면 clear될 것이다(non-visual-mode).
- int isendwin()
다음에 refresh()를 가지고 endwin()이 호출되면 TRUE를 반환하고 그렇지 않으면 FALSE를 반환한다. - void delscreen(SCREEN* sp)
SCREEN이 더이상 필요하지 않을 때, endwin() 후에 점유하고 있는 자원들을 모두 풀어주기 위해 delscreen(SCREEN)을 호출하라. (Note:아직 구현되지 않음)
8.5 윈도우 (Windows)
윈도우즈(windows)는 생성되고 삭제되고 이동되고 복사되고 사용되고 중복되어질 수 있다.
- WINDOW *newwin(nlines, ncols, begy, begx)
begy와 begx는 좌측상단 구석의 윈도우 좌표이다. nlines는 라인 수를 나타내는 정수이고 ncols는 컬럼 수를 나타내는 정수이다.그림 8.1:Ncurses - newwin을 위한 스키마(scheme)
우리의 윈도우의 좌측상단 구석은 10라인의 10컬럼이고 위도우는 10라인과 60컬럼을 갖는다. nlines가 제로이면, 윈도우는 LINES-begy개의 row를 갖을 것이다. 같은 방법으로 ncols이 제로이면 윈도우는 COLS-begx개의 컬럼을 갖을 것이다.
모든 아규먼트에 제로를 가지고 newwin(...)를 호출할 때:
열려진 윈도우는 화면의 크기를 갖을 것이다.
어떤 차원(demension)을 가지고 있건 화면의 중앙에 윈도우를 열고자 할 때:
이것은 화면의 중앙에 22라인과 70컬럼을 가진 위도우를 열 것이다. 윈도우를 열기 전에 화면의 크기를 체크하라. 리눅스 콘솔에서 우리는 25 이상의 라인과 80이상의 컬럼을 갖지만, xterms에서는 이것은 일정하지 않다(resizable하다).
더 자세한 설명을 위해 예제 디렉토리에 있는 .c를 봐라.
- int delwin(win)
윈도우 win을 삭제하라. 서브윈도우들이 있으면 win 전에 그것들을 삭제하라. win에 의해 점유되어진 모든 자원들은 자유로와 질 것이다. endwin()를 호출하기 전에 열려져 있는 모든 윈도우를 삭제하라. - int mvwin(win, by, bx)
by,bx 좌표로 윈도우를 이동시킨다. 화면의 가장자리 밖으로 윈도우를 이동하고자 한다면, 아무것도 수행되지 않고 ERR가 반환된다. - WINDOW *subwin(origwin, nlines, ncols, begy,begx)
origwin의 중앙에 서브윈도우를 반환한다. 두 윈도우들(origwin 또는 new one) 중 하나를 바꾸고자 할 때 이 변화는 양쪽 윈도우 모두에 반영될 것이다. 다음의 refresh() 전에 touchwin(origwin)를 호출하라.begy와 begx는 origwin이 아니라 화면에 비례한다.
- WINDOW *derwin(origwin, nlines, ncols, begy, begx)
subwin(...)와 같이 화면에서 begy, begx와 연관된 윈도우 origwin을 제외한다. - int mvderwin(win, y, x)
win을 부모 윈도우 안으로 이동시킨다. (NOTE:아직 구현되지 않음) - WINDOW *dupwin(win)
윈도우 win을 복사한다. - int syncok(win, bf)
void wsyncup(win)
void wcursyncup(win)
void wsyncdown(win)
(Note:아직 구현되지 않음) - int overlay(win1, win2)
int overwrite(win1, win2)
overlay(...)는 모든 텍스트를 공백은 복사하지 않고 win1에서 win2로 복사한다. overwrite(...)는 공백을 복사하는 것을 제외하고는 같다. - int copwin(win1, win2, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol, overlay)
overlay(...), overwrite(...)와 비슷하지만 윈도우의 어떤 영역으로 복사할 것인지 통제권(control)을 제공한다.
8.6 출력 (Output)
- int addch(ch)
int waddch(win, ch)
int mvaddch(y, x, ch)
int mvwaddch(win, y, x, ch)
이러한 함수들은 윈도우에 문자 출력을 위해 사용된다. 함수들은 윈도우를 조종할 것이고 화면에 출력하기위해 refresh()을 호출해야 한다. addch(...)와 waddch(...)는 윈도우나 win안에 ch 문자를 출력한다. mvaddch(...)와 mvwaddch(...)은 y, x의 위치로 커서를 이동하는 것을 제외하고는 똑같이 동작한다. - int addstr(str)
int addnstr(str, n)
int waddstr(win, str)
int waddnstr(win, str, n)
int mvaddstr(y, x, str)
int mvaddnstr(y, x, str, n)
int mvwaddstr(win, y, x, str)
int mvwaddnstr(win, y, x, str, n)
이러한 함수들은 윈도우에 문자열을 쓰며 addch(...)의 호출을 연속적으로 수행하는 것과 같다. str은 널(null)로 끝나는 문자열이다("blafoo\0"). 다른 함수들이 그냥 쓰는 반면에 w를 가진 함수들은 윈도우 win에 문자열 str을 쓴다. n을 가진 함수들은 str 중 n개의 문자를 쓴다. n이 -1이면, 전체 문자열이 쓰여진다. - int addchstr(chstr)
int addchnstr(chstr, n)
int waddchstr(win, chstr)
int waddchnstr(win, chstr, n)
int mvaddchstr(y, x, chstr)
int mvaddchnstr(y, x, chstr, n)
int mvwaddchstr(win, y, x, chstr)
int mvwaddchnstr(win, y, x, chstr, n)
이러한 함수들은 chstr을 윈도우 이미지(또는 win)로 복사한다. 시작하는 위치는 현재 커서의 위치이다. n을 가진 함수들은 chstr 중 n개의 문자를 쓴다. n이 -1이면, 전체 문자열 chstr이 쓰여진다. 커서는 옮겨지지 않고 컨트롤 문자 체크(control character check)는 이루어 지지 않는다. 이러한 함수들은 addstr(...) 루틴들보다 더 빠르다. chstr은 chtype 배열의 포인터이다. - int echochar(ch)
int wechochar(win, ch)
refresh()(wrefresh(win))에 의해 따라오는 addch(...)(waddch(...)) 호출과 같다
8.6.1 형식화된 출력 (Formatted Output)
- int printw(fmt, ...)
int wprintw(win, fmt, ...)
int mvprintw(y, x, fmt, ...)
int mvwprintw(win, y, x, fmt, ...)
int vwprintw(win, fmt, va_list)
이러한 함수들은 printf(...)와 연관이 있고 아주 닮았다.패키지 안에서 printf(...)은 형식화된 출력을 위해 사용되어진다. 출력 문자열을 정의할 수 있고 그안에서 다른 타입의 변수들을 포함할 수 있다. 더 자세한 것은 8.1.1장을 참조하라
vwprintw(...)을 사용하기 위해 .h를 포함(include)해야한다.
8.6.2 문자/줄 입력 (Insert Characters/Lines)
- int insch(c)
int winsch(win, c)
int mvinsch(y, x, c)
int mvwinsch(win, y, x, c)
문자 ch는 커서의 왼쪽에 삽입되고 모든 문자들은 오른쪽으로 한자리씩 이동된다. 줄의 오른쪽 끝에 있는 문자를 잃어버릴 수도 있다. - int insertln()
int winddelln(win, n)
양수 n에 대해 이러한 함수들은 적절한 윈도우에 n개의 줄을 커서의 위쪽에 삽입한다.(그래서 n개의 바닥쪽의 줄을 잃어버리게 된다.) n이 음수인 경우, 커서 아래의 n개의 줄이 삭제되고 나머지가 위로 이동한다. - int insstr(str)
int insnstr(str, n)
int winsstr(win, str)
int winsnstr(win, str, n)
int mvinsstr(y, x, str)
int mvinsnstr(y, x, str, n)
int mvwinsstr(win, y, x, str)
int mvwinsnstr(win, y, x, str, n)
이러한 함수들은 현재 줄안에 커서의 왼쪽에 str을 삽입한다.(줄에 꼭 맞을 만큼의 문자들) 커서의 오른쪽에 있는 문자들은 오른쪽으로 이동하고 줄의 끝에 도달하게 되면 잃어 버리게 된다. 커서의 위치는 변하지 않는다.y와 x는 str이 삽입되기 전에 커서가 이동할 좌표이고 n은 삽입될 문자의 수이다. (n=0이면 전체 문자열이 삽입된다.)
8.6.3 문자/줄 지우기 (Delete Characters/Lines)
- int delch()
int wdelch(win)
int mvdelch(y, x)
int mvwdelch(win, y, x)
커서 왼쪽의 문자를 지우고 커서 오른쪽의 남아있는 문자들을 왼쪽으로 한자리씩 위치를 이동시킨다.y와 x는 삭제하기 전에 커서가 이동할 좌표이다.
- int deleteln()
int wdeleteln(win)
커서 아래의 줄을 지우고 모든 나머지 줄들을 한자리씩 위로 위치를 이동시킨다. 부가적으로, 윈도우의 바닥 줄은 지워질 것이다.
8.6.4 상자와 줄 (Boxes and Lines)
- int border(ls, rs, ts, bs, tl, tr, bl, br)
int wborder(win, ls, rs, ts, bs, tl, tr, bl, br)
int box(win, vert, hor)
윈도우(또는 win)의 가장자리 주위에 경계를 그린다. 다음의 테이블에서 box(...) 호출시 제로(zero)일 때, 그들의 디폴트 값과 문자를 볼 수 있다.Table 8.3:Ncurses - border characters
Figure 8.2:Ncurses - box characters
- int vline(ch, n)
int wvline(win, ch, n)
int hline(ch, n)
int whline(win, ch, n)
이러한 함수들은 현재 커서 위치에서 시작하는 수직선 또는 수평선을 그린다. ch는 사용하는 문자이고 n은 그려지는 문자의 수이다. 커서 위치는 변하지 않는다.
8.6.5 백그라운드 문자 (Background Character)
- void bkgdset(ch)
void wbkgdset(win, ch)
백그라운드(background) 문자와 화면 또는 윈도우의 속성을 지정한다. ch안의 속성은 윈도우 안에 있는 모든 공백이 아닌 문자와 OR되어진다. 백그라운드는 윈도우의 일부이고 스크롤링, 입력, 출력 에 의해 변하지 않는다. - int bkgd(ch)
int wbkgd(win, ch)
백그라운드 문자를 ch의 속성으로 바꾼다.
8.7 입력 (Input)
- int getch()
int wgetch(win)
int mvgetch(y, x)
int mvwgetch(win, y, x)
getch()는 지연 모드(delay mode)가 지정되었는지 아닌지에 따른 방식으로 단말기로 부터 입력을 읽는다. 지연(delay)이 on인 경우, getch()는 키가 눌려질 때까지 기다리고 그렇지 않으면 입력 버퍼안의 키를 반환하고 버퍼가 비어있으면 ERR을 반환한다. mvgetch(...)와 mvwgetch(...)는 먼저 y,x 위치로 커서를 이동시킨다. w 함수들은 윈도우 win과 연관된 단말기로 부터 입력을 읽는다.keypad(...)가 enable되어 있으면, getch()는 기능키(function key)가 눌려질 때 .h에 KEY_* 매크로 처럼 정의된 코드를 반환한다. ESCAPE가 눌려질 때(이것이 기능키의 시작일 수 있음) ncurses는 one second timer를 시작시킨다. 이 시간 안에 keystroke의 나머지가 끝나지 않는다면, 키는 반환된다. 그렇지 않으면, 기능키값이 반환된다. (필요하다면, second timer를 사용하지 않기위해 notimeout()을 사용하라)
- int ungetch(ch)
입력 버퍼의 뒤에 ch 문자를 넣는다. - int getstr(str)
int wgetstr(win, str)
int mvgetstr(y, x, str)
int mvwgetstr(win, y, x, str)
int wgwrnstr(win, str, n)
이러한 함수들은 newline을 받을 때까지 getch()의 호출을 연속적으로 수행한다. 문자들은 str안에 놓여있다.(getstr(...)를 호출하기 전에 문자 포인터(character pointer)를 위해 메모리를 할당하는 것을 잊지 말아라) echo가 enable되어 있으면 문자열은 echo되어지고 (echo를 사용하지 않기위해 noecho()를 사용하라) 사용자의 kill과 문자들의 삭제는 해석되어진다. - chtype inch()
chtype winch(win)
chtype mvinch(y, x)
chtype mvwinch(win, y, x)
이러한 함수들은 화면이나 윈도우로 부터 문자를 반환한다. 반환값의 타입은 속성 정보를 포함하는 chtype이기 때문이다. 이 정보는 A_* 상수를 사용하는 문자로 부터 추출되어질 수 있다. (표 8.4를 참조하라) - int instr(str)
int innstr(str, n)
int winstr(win, str)
int winnstr(win, str, n)
int mvinstr(y, x, str)
int mvinnstr(y, x, str, n)
int mvwinstr(win, y, x, str)
int mvwinnstr(win, y, x, str, n)
화면 또는 윈도우로 부터 character string을 반환한다.(Note:아직 구현되지 않음) - int inchstr(chstr)
int inchnstr(chstr, n)
int winchstr(win, chstr)
int winchnstr(win, chstr, n)
int mvinchstr(y, x, chstr)
int mvinchnstr(y, x, chstr, n)
int mvwinchstr(win, y, x, chstr)
int mvwinchnstr(win, y, x, chstr, n)
화면 또는 윈도우로 부터 chtype string을 반환한다. 문자열안에 모든 문자에 대한 속성 정보가 포함되어있다. (Note:아빅 구현되지 않음. lib_inchstr은 ncurses lib에 포함되지 않음)
8.7.1 형식화된 입력 (Formatted Input)
- int scanw(fmt, ...)
int wscanw(win, fmt, ...)
int mvscanw(y, x, fmt, ...)
int mvwscanw(win, y, x, fmt, ...)
int vwscanw(win, fmt, va_list)
이것들은 scanf(...)와 비슷하다.(8.1.2장을 참조하라) wgetstr(...)은 호출되어지고 그 결과는 scan를 위한 입력처럼 사용되어진다.
8.8 선택사항 (Options)
- 8.8.1 출력 선택사항 (Output Options)
- 8.8.2 입력 선택사항 (Input Options)
- 8.8.3 단말기 속성 (Terminal Attributes)
- 8.8.4 사용 선택사항 (Use Options)
8.8.1 출력 선택사항 (Output Options)
- int idlok(win, bf)
void idcok(win, bf)
윈도우의 단말기의 삽입/삭제 특성을 사용 가능하게(enable) 하거나 사용 불가능하게(disable) 한다. (idlok(...)는 줄(line)에 대해 idcok(...)은 문자에 대해 사용) (Note:idcok(...)은 아직 구현되지 않음) - void immedok(win, bf)
TRUE로 지정되면, 윈도우 win에 대한 모든 변화는 물리적인 화면을 refresh하게 만든다. 이것은 프로그램의 성능을 감소시킬 수 있다. 따라서 디폴트 값은 FALSE이다. (Note:아직 구현되지 않음) - int clearok(win, bf)
bf가 TRUE이면, wrefresh(win)의 다음 호출은 화면을 clear하고 완벽하게 다시 그릴 것이다. (vi 에디터에서 CTRL+L을 눌렀을 때처럼) - int leaveok(win, bf)
기본 동작(default behavior)은 ncurses가 물리적인 커서를 윈도우의 마지막 refresh가 발생한 같은 장소에 놓는 것이다. 커서를 사용하지 않는 프로그램들은 leaveok(...) TRUE를 지정할 수 있고 커서를 움직이는데 필요한 일반적인 시간을 줄일 수 있다. 게다가, ncurses는 단말기 커서를 안보이게 만들려고 할 것이다. - int nl()
int nonl()
newline을 위한 변환을 통제한다. nl()은 출력에서 carriage return과 line feed를 newline으로 변환시킨다. nonl()은 변환을 하지 않는다. 변환을 하지않토록된 ncurses는 커서 이동을 더 빠르게 할 수 있다.
8.8.2 입력 선택사항 (Input Options)
- int keypad(win, bf)
TRUE이면, 입력을 위해 기다리고 있을 때 사용자 단말기의 키보드 상에서 키패드의 사용이 가능하다. Ncurses는 키패드의 기능(function)과 화살표(arrow) 키들을 위해 KEY_* 처럼 .h에 정의된 키 코드를 반환할 것이다. 이것은 숫자 블록(numerical block)과 커서 키들을 사용할 수 있으므로 PC 키보드에서 매우 유용하다. - int meta(win, bf)
TRUE이면, getch()로 부터 반환되는 키 코드들은 8-bit-clean이다. (최상위 비트는 떼어낼 수 없다.) - int cbreak()
int nocbreak()
int crmode()
int nocrmode()
cbreak()과 nocbreak()은 단말기의 CBREAK 모드를 on 또는 off로 전환시킬 것이다. CBREAK가 on일 때, 읽기로 부터의 입력은 즉시 프로그램에서 사용가능하고 off일 때, 입력은 newline이 발생할 때까지 버퍼에 저장될 것이다. (Note:crmode()와 nocrmode()은 향상된 호환성이 있지만, 그들을 사용하지 말아라) - int raw()
int noraw()
RAW 모드를 on 또는 off로 만든다. RAW는 RAW 모드에서는 특수 문자 처리가 이루어지지 않는다는 것을 제외하고는 CBREAK와 같다. - int echo()
int noecho()
사용자에 의해 타이핑된 입력을 echo하기위해 echo()를 지정하고 침묵하기 위해서는 noecho()를 지정한다. - int halfdelay(t)
cbreak()처럼 t 초간 지연(delay)한다. - int nodelay(win, bf)
단말기는 차단(blocking) 모드로 지정되지 않는다. cetch()는 입력이 준비되어있지 않으면 ERR을 반환할 것이다. FALSE가 지정되어 있으면, getch()는 키가 눌려질 때까지 기다릴 것이다. - int timeout(t)
int wtimeout(win, t)
halfdelay(t)와 nodelay(win,bf) 대신 이러한 함수들의 사용이 추천된다. getch()의 결과는 t의 값에 따라 결정된다. t가 양수이면, 읽기는 t milliseconds 간 차단되어진다(blocked). t가 제로이면, 차단(blocking)은 수행되지 않는다. t가 음수일 때 프로그램은 입력이 가능할 때까지 차단한다. - int notimeout(fd)
bf가 TRUE이면, getch()는 ESCAPE과 같은 키로 시작하는 시퀀스(sequence)를 입력받고 번역하기 위해 특별한 (1초 길이의)타이머를 사용할 것이다. - int typeahead(fd)
fd가 -1이면 typeahead 체크는 수행되어지지 않을 것이고, 그렇지 않으면 ncurses는 이러한 체크를 위해 파일 식별자(file descriptor) fd를 사용할 것이다. - int intrflush(win, bf)
bf가 TRUE로 사용가능할 때 단말기 상에서 눌려진 인터럽트(interrupt) 키(quit, break, ...)는 tty 드라이버(driver) 큐(queue) 안의 모든 출력을 몰아낼 것이다. - void noqiflush()
void qiflush()
(Note:아직 구현되지 않음)
8.8.3 단말기 속성 (Terminal Attributes)
- int baudrate()
bps로 단말기의 속도를 반환한다. - char erasechar()
현재 erase 문자를 반환한다. - char killchar()
현재 kill 문자를 반환한다. - int has_ic()
int has_il()
has_ic()는 단말기가 문자를 삽입/삭제할 능력을 가지고 있으면 TRUE를 반환한다. has_il()는 단말기가 줄을 삽입/삭제할 능력을 가지고 있으면 TRUE를 반환한다. 그렇지 않으면 함수들은 ERR를 반환한다. (Note:아직 구현되지 않음) - char *longname()
반환된 포인터는 현재의 단말기의 기술에 접근권을 준다. - chtype termattrs()
(Note:아직 구현되지 않음) - char *termname()
사용자 환경으로 부터 TERM의 내용을 반환한다.(Note:아직 구현되지 않음)
8.8.4 사용 선택사항 (Use Options)
윈도우와 단말기의 사용을 성멸하기 위해 윈도우 선택사항(option)과 단말기 모드에 대해 살펴 보았다.
먼저, 리눅스상에서 키패드를 사용할 수 있어야 한다. 이것은 PC 키보드 상에서 커서 키와 숫자 블럭의 사용을 허락한다.
입력의 중요한 두 가지 타입이 있다.:
- 프로그램은 사용자가 키를 입력(enter)하기를 원하고 이 키에 따라 함수를 호출할 것이다. (예를 들면, "끝내려면 'q'를 누르시오"와 같이 그리고 'q'를 기다린다.)
- 프로그램은 화면상의 마스크 안에서 사용자에 의해 타이핑된 문자들의 문자열을 원한다. 예를 들면: 데이타베이스 안의 디렉토리 또는 어드레스(address).
첫째로 우리는 다음의 선택사항(option)과 모드들을 사용하고 while loop는 정확하게 작업할 것이다.
프로그램은 키가 눌려질 때까지 멈추어 있을 것이다. 키가 q이면 우리는 끝내기(quit) 함수를 호출하고 그렇지 않으면 다른 입력을 기다린다.
switch 문장은 우리가 바라는 것과 일치하는 입력함수를 가질 때까지 확장될 수 있다. 한 예로, 특별한 키를 체크하기 위해 KEY_* 매크로들을 사용하라.
키보드에서 커서 키들을 위해. 파일 뷰어(viewer)를 위해 loop가 이것처럼 보일 수 있다.:
둘째로, 우리는 echo()를 지정할 필요가 있고 사용자에 의해 타이핑된 문자들은 화면에 인쇄되어질 것이다. 원하는 위치에 문자가 인쇄되도록 하기위해 move 또는 wmove(...)를 사용하라.
또는 우리는 마스크를 가지고 윈도우를 열 수 있고 (윈도우의 것들보다 다른 몇몇 색상들이 이것을 수행할 것이다) 사용자에게 문자열 입력을 요청한다.
보다 자세한 설명을 위해 예제 디렉토리에 있는 .c를 보아라.
8.9 윈도우와 줄 지우기 (Clear Window and Lines)
- int erase()
int werase(win)
werase(...)와 erase()는 윈도우 win상의 모든 위치에 공백을 복사한다. 예를 들어, 윈도우에 색상 속성을 지정하고 werase()를 호출할 때, 윈도우는 color가 될 것이다. 흰색 위에 검정색처럼 다른 속성을 정의하여 자신만의 erase 함수를 만들때 COLOR_PAIRS에 약간의 문제가 있다. (이것은 WINDOW 구조에 접근하는 하위 수준(low level)이다.):문제는 ncurses가 때때로 화면이 공백일 때 윈도우 속성들을 사용할 수 없다는 것이다. 예를 들어, _clrtoeol.c 안에 BLANK는 정의되어 있다.
그래서 다른 윈도우 속성들은 줄이 지워지는 동안에 잃어버린다.
- int clear()
int wclear(win)
erase와 같지만 clearok()를 지정할 것이다. (화면은 다음 refresh에 의해 지워(clear)진다.) - int clrtobot()
int wclrtobot(win)
현재 커서 줄(시작점은 커서의 오른쪽 한 문자이다)과 커서 아래의 줄을 지운다(clearing). - int clrtoeol()
int wclrtoeol(win)
커서로 부터 끝까지 현재 줄의 오른쪽을 지운다.
8.10 단말기 업데이트 (Updating the Trminal)
개요에 쓰였던 것처럼, ncurses 윈도우들은 메모리 안에 있는 이미지들이다. 이것은 윈도우에서의 어떤 변화가 refresh가 수행될 때까지 물리적인 화면에 인쇄되지 않는다는 것을 의미한다. 이것은 많은 조종이 있을 수 있기 때문에 화면에 대한 출력을 최적화하고 화면에 그것을 인쇄하기 위해 refresh를 한번 호출한다. 그렇지 않으면, 모든 변화가 화면에 인쇄되어 지고 프로그램의 성능 (performance)를 감소시킨다.
- int refresh()
int wrefresh(win)
refresh()는 단말기로 복사를 하고 wrefresh(win)는 윈도우 이미지로 복사한다. - int wnoutrefresh(win)
int doupdate()
wnoutrefresh(win)는 오직 윈도우 win으로 복사한다. 이것은 단말기에 대한 출력이 수행되지는 않지만 가상의 화면에 실제적으로 프로그래머가 원하는 대로 보여짐을 의미한다. doupdate()는 단말기에 출력을 수행할 것이다. 프로그램은 여러가지 윈도우들을 바꿀 수 있고 모든 윈도우에 대해 wnoutrefresh(win)를 호출할 수 있고 오직 한번 물리적인 화면을 업데이트하기 위해 doupdate()를 호출할 수 있다.예를 들어, 두개의 윈도우를 가지는 다음의 프로그램이 있다. 텍스트의 몇몇 줄을 변경하여 양쪽 윈도우들을 바꾼다. wrefresh(win)을 가지고 changewin(win)를 write할 수 있다.
이것은 ncurses가 단말기를 두번 업데이트하게 하여 실행을 느리게 한다. doupdate()를 가지고 changewin(win)와 main 함수를 변경시키고 성능(performance)을 향상시킨다.
- int redrawwin(win)
int wredrawln(win, bline, nlines)
몇몇 줄이나 전체 화면이 새로운 것을 쓰기 전에 없어져야 할 때, 이러한 함수들을 사용한다. (아마도 몇몇 줄이 쓸모없어 졌을 때) - int touchwin(win)
int touchline(win, start, count)
int wtouchln(win, y, n, changed)
int untouchwin(win)
ncurses에 전체 윈도우 win 또는 start up으로 부터 start+count까지 줄들이 조종되었음을 알린다. 예를 들어, 몇몇 윈도우가 중첩되었을 때, 한 윈도우에 대한 변화는 다른 것들로 부터 이미지에 영향을 받지 않을 것이다.wtouchln(...)은 y로 부터 시작하여 n개의 줄을 건드릴 것이다. change가 TRUE이면 그 줄들은 변경되고(touched,changed) 그렇지 않으면 변경되지 않는다(untouched,unchanged).
untouchwin(win)는 refresh의 마지막 호출 이후 윈도우 win에 unchanged 표시를 할 것이다.
- int is_linetouched(win, line)
int is_wintouched(win)
이러한 함수들을 가지고 줄 line 또는 윈도우 win이 refresh()의 마지막 호출 이후에 변경이 있었는지를 체크할 수 있다.
8.11 비디오 속성과 색상 (Video Attributes and Color)
속성은 화면에 문자를 인쇄할 때 사용되는 특별한 단말기 속성이다. 문자들은 굵게,밑줄,깜빡임 등으로 인쇄될 수 있다. ncurses에서 출력을 보다 좋게 보이도록 속성들을 on 또는 off로 전환할 수 있는 능력을 갖는다. 사용가능한 속성들이 다음의 표에 정리되어 있다.
표 8.4:Ncurses - 속성들
ncurses는 칼라를 지원하는 단말기에서 사용할 수 있는 8가지 색상을 정의한다. 먼저, start_color()를 가지고 색상 자료 구조(color data structures)를 초기화하고 has_colors()를 가지고 단말기의 능력을 체크한다. start_color()는 COLORS, 단말기가 지원하는 최대 색상수와 COLOR_PAIR, 정의할 수 있는 색상 쌍(color pairs)의 최대수 를 초기화한다.
표 8.5:Ncurses - colors
속성은 OR operator를 가지고 조합되어질 수 있다.
int color_content(color, r, g, b)
색상을 위해 r,g,b의 색상 구성요소(components)를 얻는다.
어떻게 속성과 색상을 어떻게 조합할 것인가? 리눅스에서의 콘솔처럼 몇몇 단말기는 칼라를 갖고 몇몇은 그렇지 않다(xterm,vs100 등등). 다음의 코드는 그 문제를 해결해야만 한다.
먼저, CheckColor 함수는 start_color()를 가지고 색상을 초기화한다. 현재 단말기가 색상을 가지고 있다면 has_colors() 함수는 TRUE를 반환할 것이다. 우리는 이것을 체크하고 포그라운드(foreground)와 백그라운드(background) 색상들을 조합하기 위해 init_pair(...) 와 지정된 윈도우를 위해 이러한 쌍(pairs)을 지정하기 위해 wattrset(...)를 호출한다. 또 한편으로, 흑백 단말기를 가지고 있다면, 속성을 지정하기 위해 wattrset(...)를 혼자 사용할 수 있다.
xterm에서 색상(color)을 얻기 위해 내가 발견한 가장 좋은 방법은 Midnight Commander로 부터 terminfo 개체를 얻는 ansi_xterm을 사용하는 것이다. ansi_xterm과 Midnight Commander (mc-x.x.tar.gz)의 소스를 구하라. ansi_xterm을 컴파일하고 mc-x.x.tar.gz acchive로 부터 xterm.ti와 vt100.ti를 가지고 tic을 사용하라. ansi_xterm을 실행시켜보고 테스트 해 보아라.
8.12 커서와 윈도우 좌표 (Cursor and Window Coordinates)
- int move(y, x)
int wmove(win, y, x)
move()는 커서를 y, x로 이동시키고, wmove(win)는 윈도우 win으로 부터 커서를 이동시킨다. 입력/출력 함수들을 위해 지정된 함수들이 호출되기 전에 커서를 이동시키는 부가적인 매크로들이 정의된다. - int curs_set(bf)
이것은 단말기아 이러한 능력을 가지고 있다면, 커서의 눈에 보이는 상태를 on 또는 off로 전환시킬 것이다. - void getyx(win, y, x)
getyx(...)는 현재의 커서 위치를 반환할 것이다.(Note:이것은 매크로이다.) - void getparyx(win, y, x)
win이 서브 윈도우일 때, getparyx(...)는 부모 윈도우와 연관된 윈도우 좌표를 y와 x에 저장할 것이다. 그렇지 않으면 y와 x는 -1이다. (Note:아직 구현되지 않음) - void getbegyx(win, y, x)
void getmaxyx(win, y, x)
int getmaxx(win)
int getmaxy(win)
win의 시작과 크기 좌표를 y와 x에 저장한다. - int getsyx(int y, int x)
int setsyx(int y, int x)
가상 화면의 커서을 y와 x에 저장하거나 커서를 지정한다. y와 x가 -1이고 getsyx(...)를 호출할 때, leaveok가 지정되어진다.
8.13 스크롤 (Scrolling)
- int scrollok(win, bf)
TRUE이면, 윈도우 win의 텍스트는 커서가 하단 오른쪽 구석에 있고 한문자가 타이핑 되어질 때 (또는 newline) 한 줄씩 위로 스크롤 되어질 것이다. FALSE이면, 커서는 같은 위치에 남겨진다.on으로 전환될 때 윈도우의 내용들은 다음의 함수들을 가지고 스크롤 되어질 수 있다. (Note:윈도우의 마지막 줄에 new line이 인쇄되면, 또한 스크롤 되어질 것이다. scrollok(...)는 주의해야 한다 그렇지 않으면 터무니없는 결과를 얻을 것이다.
- int scroll(win)
이 함수는 윈도우를(자료구조안에 있는 줄들을) 한줄씩 위로 스크롤할 것이다. - int scrl(n)
int wscrl(win, n)
이러한 함수들은 윈도우 또는 win을 정수 n의 값에 따라 위로 또는 아래로 스크롤할 것이다. n이 양수이면 윈도우는 n줄 위로 스크롤될 것이고 반대로 n이 음수이면 윈도우는 n줄 아래로 스크롤될 것이다. - int setscrreg(t, b)
int wsetscrreg(win, t, b)
소프트웨어 스크롤링 지역을 지정한다.
다음의 코드는 화면상에서 어떻게 스크롤링 효과를 얻을 것인가를 설명해야만 한다. 예제 디렉토리에 있는 .c를 살펴 보아라.
우리는 18줄과 66컬럼을 가진 윈도우가 있고 그 안의 텍스트를 스크롤하기를 원한다. S[]는 텍스트를 가지고 있는 문자 배열이다. Max_s는 s[]에 있는 마지막 줄의 번호이다. Clear_line는 현재 커서 위치로 부터 윈도우로 부터 현재의 속성을 가지는 줄의 끝까지 공백 문자를 인쇄할 것이다.(clrtoeol이 하는 것처럼 A_NORMAL이 아니다.) Beg는 현재 화면상에 보여지는 s[]로 부터의 마지막 줄이다. Scroll는 함수에 무엇을 하고, 텍스트로 부터 다음(NEXT)과 이전(PREVious) 줄을 보여 주도록 일일이 말한다.
8.14 패드 (Pads)
- WINDOW *newpad(nlines, ncols)
- WINDOW *subpad(orig, nlines, ncols, begy, begx)
- int prefresh(pad, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol)
- int pnoutrefresh(pad, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol)
- int pechochar(pad, ch)
8.15 소프트-라벨 (Soft-labels)
- int slk_init(int fmt)
- int slk_set(int labnum, char *label, int fmt)
- int slk_refresh()
- int slk_noutrefresh()
- char *slk_label(int labnum)
- int slk_clear()
- int slk_restore()
- int slk_touch()
- int slk_attron(chtype attr)
int slk_attrset(chtype attr)
int slk_attroff(chtype attr)
이러한 함수들은 attron(attr), attrset(attr), attroff(attr)와 관련이 있다. 아직 구현되지 않음.
8.16 잡동사니 (Miscellaneous)
- int beep()
- int flash()
- char *unctrl(chtype c)
- char *keyname(int c)
- int filter()
(Note:아직 구현되지 않음.) - void use_env(bf)
- int putwin(WINDOW *win, FILE *filep)
(Note:아직 구현되지 않음.) - WINDOW *getwin(FILE *filep)
(Note:아직 구현되지 않음.) - int delay_output(int ms)
- int flushinp()
8.17 Low-level 접근 (Access)
- int def_prog_mode()
- int def_shell_mode()
- int reset_prog_mode()
- int reset_shell_mode()
- int resetty()
- int savetty()
- int ripoffline(int line, int (*init)(WINDOW *, int))
- int napms(int ms)
8.18 화면 덤프 (Screen Dump)
- int scr_dump(char *filename)
(Note:아직 구현되지 않음.) - int scr_restore(char *filename)
(Note:아직 구현되지 않음.) - int scr_init(char *filename)
(Note:아직 구현되지 않음.) - int scr_set(char *filename)
(Note:아직 구현되지 않음.)
8.19 Termcap Emulation
- int tgetent(char *bp, char *name)
- int tgetflag(char id[2])
- int tgetnum(char id[2])
- char *tgetstr(char id[2], char **area)
- char *tgoto(char *cap, int col, int row)
- int tputs(char *str, int affcnt, int (*putc)())
8.20 Terminfo 함수들(Functions)
- int setupterm(char *term, int fildes, int *errret)
- int setterm(char *term)
- int set_curterm(TERMINAL *nterm)
- int del_curterm(TERMINAL *oterm)
- int restartterm(char *term, int fildes, int *errret)
(Note: 아직 구현되지 않음.) - char *tparm(char *str, p1, p2, p3, p4, p5, p6, p7, p8, p9)
p1 - p9 long int. - int tputs(char *str, int affcnt, int (*putc)(char))
- int putp(char *str)
- int vidputs(chtype attr, int (*putc)(char))
- int vidattr(chtype attr)
- int mvcur(int oldrow, int oldcol, int newrow, int newcol)
- int tigetflag(char *capname)
- int tigetnum(char *capname)
- int tigetstr(char *capname)
8.21 디버그 함수 (Debug Function)
- void _init_trace()
- void _tracef(char *, ...)
- char *_traceattr(mode)
- void traceon()
- void traceoff()
8.22 Terminfo 능력 (Capabilities)
8.22.1 논리 능력 (Boolean Capabilities)
Variable | Cap. | Int. | Description |
Name | Code | ||
auto_left_margin | bw | bw | cub1이 컬럼 0부터 마지막 컬럼까지 포함한다(wrap) |
auto_right_margin | am | am | 단말기가 자동적으로 여백을 갖는다. |
back_color_erase | bce | ut | 화면은 백그라운드 색상으로 지원진다. |
can_change | ccc | cc | 단말기는 존재하는 색상들로 재정의될 수 있다. |
ceol_standout_glitch | xhp | xs | 표준출력은 overwritong에 의해 지워지지 않는다.(hp) |
col_addr_glitch | xhpa | YA | 오직 hpa/mhpa 능력을 위한 적극적인 움직임 |
cpi_changes_res | cpix | YF | 문자 pitch의 변화는 해상도를 변화시킨다. |
cr_cancels_micro_mode | crxm | YB | cr를 사용하여 매크로 모드를 off로 전환한다. |
eat_newline_glitch | xenl | xn | newline은 80cols 이후에는 무시된다. |
erase_overstrike | eo | eo | 공백을 가지고 overstrikes를 지울 수 있다. |
generic_type | gn | gn | 일반적인 줄(line) 타입 (e.g.,, dialup, switch) |
hard_copy | hc | hc | 단말기를 하드카피한다. |
hard_cursor | chts | HC | 커서를 보기 어렵다. |
has_meta_key | km | km | 메타 키를 갖는다 (패리티 비트가 지정된 shift) |
has_print_wheel | daisy | YC | 프린터는 문자 집합을 바꾸기위한 연산자(operator)가 필요하다 |
has_status_line | hs | hs | 여분의 "상태 줄"을 갖는다 |
hue_lightness_saturation | hls | hl | 단말기는 오직 HLS 색상 표기법만을 사용한다(Tektronix) |
insert_null_glitch | in | in | 삽입 모드는 널(null)을 구분한다. |
lpi_changes_res | lpix | YG | 줄(line) pitch의 변경은 해상도를 바꾼다. |
memory_above | da | da | Display는 화면 위에 계속 유지되어진다. |
memory_below | db | db | Display는 화면 아래에 계속 유지되어진다. |
move_insert_mode | mit | mi | 삽입 모드 안에서의 이동은 안전하다. |
move_standout_mode | msgr | ms | 표준출력 모드안에서의 이동은 안전하다. |
needs_xon_xoff | nxon | nx | padding은 작업하지 않을 것이고 xon/xoff가 요구된다. |
no_esc_ctl_c | xsb | xb | 붐비는 장소 (f1=escape, f2=ctrl+c) |
non_rev_rmcup | nrrmc | NR | smcup는 rmcup를 반대로 하지 않는다. |
no_pad_char | npc | NP | pad 문자는 존재하지 않는다. |
non_dest_scroll_region | ndscr | ND | 스크롤링 지역은 파괴적이지 않다. |
over_strike | os | os | 단말기 overstrikes |
prtr_silent | mc5i | 5i | 프린터는 화면에 반향(echo)하지 않는다. |
row_addr_glitch | xvpa | YD | vhp/mvpa 능력(caps)를 위한 오직 양의(positive) 움직임 |
semi_auto_right_margin | sam | YE | 마지막 컬럼의 인쇄는 cr를 야기시킨다. |
status_line_esc_ok | eslok | es | Escape은 상태줄 상에서 사용되어질 수 있다. |
dest_tabs_magic_smso | xt | xt | Tabs ruin, magic so char (Teleray 1061) |
tilde_glitch | hz | hz | Hazel-tine; 's를 인쇄할 수 없다. |
transparent_underline | ul | ul | 밑줄 문자 overstrikes |
xon_xoff | xon | xo | 단말기는 xon/xoff handshaking을 사용한다. |
8.22.2 숫자 (Numbers)
Variable | Cap. | Int. | Description |
Name | Code | ||
bit_image_entwining | bitwin | Yo | SYSV에 문서화되어 있지 않음 |
buffer_capacity | bufsz | Ya | 인쇄전에 버퍼에 저장된 바이트의 수 |
columns | cols | co | 한 줄안의 컬럼의 숫자 |
dot_vert_spacing | spinv | Yb | dots per inch안의 수평 dots의 공간(spacing) |
dot_horz_spacing | spinh | Yc | pins per inch안의 수직 pins의 공간(spacing) |
init_tabs | it | it | Tabs 최초로 모든 # 공간(spaces) |
label_height | lh | lh | 각각의 라벨안의 rows |
label_width | lw | lw | 각각의 라벨안의 컬럼(columns) |
lines | lines | li | 화면 또는 페이지의 줄(line) 수 |
lines_of_memory | lm | lm | 양수이면 메모리안의 줄 수, 0은 변함을 의미. |
magic_cookie_glitch | xmc | sg | smso 또는 rmso에 의해 남겨진 공백 문자의 수 |
max_colors | colors | Co | 화면상의 최대 색상의 수 |
max_micro_address | maddr | Yd | micro_..._address안의 최대값 |
max_micro_jump | mjump | Ye | parm_..._micro안의 최대값 |
max_pairs | pairs | pa | 화면상의 색상-쌍(color-pairs)의 최대 수 |
micro_col_size | mcs | Yf | micro 모드일 때, 문자의 step 크기(size) |
micro_line_size | mls | Yg | micro 모드일 때, 줄(line) step 크기(size) |
no_color_video | ncv | NC | 색상을 사용할 수 없는 비디오 속성 |
number_of_pins | npins | Yh | print-head안의 pin의 수 |
num_labels | nlab | Nl | 화면상의 라벨의 수 |
output_res_char | orc | Yi | units per line 안의 수평 해상도 |
output_res_line | orl | Yj | units per line 안의 수직 해상도 |
output_res_horz_inch | orhi | Yk | units per inch 안의 수평 해상도 |
output_res_vert_inch | orvi | Yl | units per inch 안의 수직 해상도 |
padding_baud_rate | pb | pb | cr/nl padding이 필요한 곳의 가장 낮은 baud |
virtual_terminal | vt | vt | 가상의 단말기 번호 (UNIX system) |
width_status_line | wsl | ws | 상태줄안의 컬럼 번호 |
(다음의 숫자 능력들(numeric capabilities)은 SYSV 용어 구조안에 표현되어 있지만, 아직 주요 페이지에 문서화되어 있지 않다. 주석문들은 용어 구조 헤더에 있다.)
bit_image_type | bitype | Yp | bit-image 장치의 타입 |
buttons | btns | BT | 마우스 버튼의 수 |
max_attributes | ma | ma | 단말기가 다룰 수 있는 최대한 조합된 속성 |
maximum_windows | wnum | MW | 정의될 수 있는 윈도우의 최대 수 |
print_rate | cps | Ym | char per second의 인쇄 비율 |
wide_char_size | widcs | Yn | double wide 모드의 문자 step 크기(size) |
8.22.3 문자열 (Strings)
Variable Cap. Int. DescriptionName Code
acs_chars acsc ac 그래픽 문자집합 쌍들 - def=vt100
alt_scancode_esc scesa S8 scancode emulation을 위한 esc를 교체한다 (디폴트는 vt100)
back_tab cbt bt back tab (P)
bell bel bl 들을 수 있는 신호 (bell)
bit_image_repeat birep Xy bit image cell을 #1 #2 times 반복한다. (tparm 사용)
bit_image_newline binel Zz bit image의 다음 row로 이동한다. (tparm 사용)
bit_image_carriage_return bucr Yv 같은 row의 시작점으로 이동한다. (tparm 사용)
carriage_return cr cr Carriage return (P*)
change_char_pitch cpi ZA inch당 문자의 수를 변경한다.
change_line_pitch lpi ZB inch당 줄(line)의 수를 변경한다.
change_res_horz chr ZC 수평 해상도를 변경한다.
change_res_vert cvr ZD 수직 해상도를 변경한다.
change_scroll_region csr cs 줄(line) #1에서 부터 #2까지 변경한다. (vt100) (PG)
char_padding rmp rP ip와 같지만 삽입 모드일 때
char_set_names csnm Zy 문자 집합 이름들의 목록
clear_all_tabs tbc ct 모든 tab stop을 지운다 (P)
clear_margins mgc MC 모든 여백을 지운다 위,아래,옆)
clear_screen clear cl 화면을 지우고 커서를 home에 위치시킨다. (p*)
clr_bol el1 cb 줄의 시작점을 지운다.
clr_eol el ce 줄의 끝을 지운다. (P)
clr_eos ed cd display의 끝을 지운다 (P*)
code_set_init csin ci 다중 코드 집합들을 위한 Init sequence
color_names colornm Yw 색상 #1을 위한 이름을 준다.
column_address hpa ch 커서 컬럼을 지정한다. (PG)
command_character cmdch CC ptototype안에서 cmd 문자를 지정할 수 있는 단말기
cursor_address cup cm 화면에 연관된 row #1 col #2로의 커서의 움직임 (PG)
cursor_down cud1 do 한줄 아래로 내린다.
cursor_home home ho Home cursor (if no cup)
cursor_invisible civis vi 커서를 보이지 않게 만든다.
cursor_left cub1 le 커서를 한칸 왼쪽으로 이동한다.
cursor_mem_address mrcup CM 메모리와 연관된 커서 어드레싱(addressing)
cursor_normal cnorm ve 커서를 정상적으로 나타나게 만든다(undo vs/vi)
cursor_right cuf1 nd 파괴되지 않는 공간 (cursor right)
cursor_to_ll ll ll 마지막 줄의 첫번째 컬럼 (if no cup)
cursor_up cuu1 up Upline (cursor up)
cursor_visible cvvis vs 커서를 보이게 만든다
define_bit_image_region defbi Yx 사각형의 bit image 지역을 정의한다 (tparm 사용)
define_char defc ZE 문자 집합 안에서의 문자를 정의한다
delete_character dch1 dc 문자를 지운다 (P*)
delete_line dl1 dl 줄(line)을 지운다 (P*)
device_type devt dv language/codeset 지원을 표시한다
dis_status_line dsl ds 상태줄을 사용할 수 없게 한다
display_pc_char dispc S1 PC 문자를 표시한다
down_half_line hd hd 반-줄 아래로 (forward 1/2 linefeed)
ena_acs enacs eA 변경된 문자 집합을 사용가능하게 한다.
end_bit_image_region endbi Yy bit image 지역을 끝낸다 (tparm 사용)
enter_alt_charset_mode smacs as 변경된 문자 집합을 시작한다 (P)
enter_am_mode smam SA 자동 여백으로 전환한다
enter_blink_mode blink mb 깜빡거림으로 전환한다
enter_bold_mode bold md 굵은체(extra bright) 모드로 전환한다.
enter_ca_mode smcup ti cup를 사용하는 프로그램을 시작하기 위한 문자열
enter_delete_mode smdc dm 모드를 지운다(enter)
enter_dim_mode dim mh half-bright 모드로 전환한다
enter_doublewide_mode swidm ZF double-wide 모드를 사용가능하게 한다
enter_draft_quality sdrfq ZG draft-quality 인쇄를 지정한다
enter_insert_mode smir im 삽입 모드 (enter);
enter_italics_mode sitm ZH 이탤릭(italics) 모드를 사용가능하게 한다
enter_leftward_mode slm ZI 왼쪽 방향의 carriage 움직임을 가능하게 한다
enter_micro_mode smicm ZJ micro-motion 능력을 가능하게 한다
enter_near_letter_quality snlq ZK NLQ 인쇄를 지정한다
enter_normal_quality snrmq ZL 일반적인 질(quality)의 인쇄를 가능하게 한다
enter_pc_charset_mode smpch S2 PC 문자 표시(display) 모드로 들어간다
enter_protected_mode prot mp 보호(protected) 모드로 전환한다
enter_reverse_mode rev mr 반전 비디오 모드로 전환한다
enter_scancode_mode smsc S4 PC scancode 모드로 들어간다
enter_secure_mode invis mk 공백(blank) 모드로 전환한다 (문자들은 안 보임)
enter_shadow_mode sshm ZM 그림자 모드(shadow-mode) 인쇄를 가능하게 한다
enter_standout_mode smso so stand out 모드를 시작한다
enter_subscript_mode ssubm ZN 아래 첨자(subscript) 인쇄를 가능하게 한다
enter_superscript_mode ssupm ZO 위첨자(superscript) 인쇄를 가능하게 한다
enter_underline_mode smul us 밑줄(underscore) 모드를 가능하게 한다
enter_upward_mode sum ZP 위로의 carriage 움직임을 가능하게 한다
enter_xon_mode smxon SX xon/xoff handshaking를 전환한다
erase_chars ech ec Erase #1 characters (PG)
exit_alt_charset_mode rmacs ae 변경된 문자 집합을 끝낸다(P)
exit_am_mode rmam RA 자동 여백을 해지한다
exit_attribute_mode sgr0 me 모든 속성을 해지한다
exit_ca_mode rmcup te cup를 사용하는 프로그램들을 끝내기 위한 문자열
exit_delete_mode rmdc ed 삭제 모드를 끝낸다
exit_doublewide_mode rwidm ZQ doublewide 인쇄를 사용 불가능하게 한다
exit_insert_mode rmir ei 삽입 모드를 끝낸다
exit_italics_mode ritm ZR 이탤릭(italic) 인쇄를 불가능하게 한다
exit_leftward_mode rlm ZS 오른쪽으로의(일반적인) carriage 움직임을 가능하게 한다
exit_micro_mode rmicm ZT micro 움직임 능력들을 사용 불가능하게 한다
exit_pc_charset_mode rmpch S3 PC character 표시를 사용 불가능하게 한다
exit_scancode_mode rmsc S5 PC scancode 모드를 사용 불가능하게 한다
exit_shadow_mode rshm ZU 그림자(shadow) 인쇄를 사용 불가능하게 한다
exit_standout_mode rmso se stand out 모드를 끝낸다
exit_subscript_mode rsubm ZV 아래첨자(subscript) 인쇄를 사용 불가능하게 한다
exit_superscript_mode rsupm ue 밑줄(underscore) 모드를 끝낸다
exit_upward_mode rum ZX 아래로의(일반적인) carriage 움직임을 사용가능하게 한다
exit_xon_mode rmxon RX xon/xoff handshaking를 해지한다
flash_screen flash vb 보여지는 bell (커서는 움직이지 않을런지 모른다)
form_feed ff ff Hardcopy terminal page eject (P*)
from_status_line fsl fs 상태 줄로부터 반환한다
init_1string is1 i1 단말기 초기화 문자열
init_2string is2 i2 단말기 초기화 문자열
init_3string is3 i3 단말기 초기화 문자열
init_file if if 포함하고 있는 파일의 이름
init_prog iprog iP 초기화를 위한 프로그램의 패스 이름
initialize_color initc Ic 색상의 정의를 초기화한다
initialize_pair initp Ip 색상의 쌍을 초기화한다
insert_character ich1 ic 문자를 삽입한다(P)
insert_line il1 al 새로운 공백 줄을 더한다(P*)
insert_padding ip ip 삽입된 문자 뒤에 패드를 삽입한다(p*)
key_a1 ka1 K1 Upper left of keypad
key_a3 ka3 K3 Upper right of keypad
key_b2 kb2 K2 Center of keypad
key_backspace kbs kb backspace key에 의해 보내진다
key_beg kbeg 1 begin key
key_btab kcbt kB back-tab key
key_c1 kc1 K4 Lower left of keypad
key_c3 kc3 K5 Lower right of keypad
key_cancel kcan 2 cancel key
key_catab ktbc ka clear-all-tabs key에 의해 보내진다
key_clear kclr kC clear screen or erase key에 의해 보내진다
key_close kclo 3 close key
key_command kcmd 4 command key
key_copy kcpy 5 copy key
key_create kcrt 6 create key
key_ctab kctab kt clear-tab key에 의해 보내진다
key_dc kdch1 kD delete character key에 의해 보내진다
key_dl kdl1 kL delete line key에 보내진다
key_down kcud1 kd terminal down arrow key에 의해 보내진다
key_eic krmir kM 삽입 모드에서 rmir or smir에 의해 보내진다
key_end kend 7 end key
key_enter kent 8 enter/send key
key_eol kel kE clear-to-end-of-line key에 의해 보내진다
key_eos ked kS clear-to-end-of-screen key에 의해 보내진다
key_exit kext 9 exit key
key_find kfnd 0 find key
key_help khlp %1 help key
key_home khome kh home key에 의해 보내진다
key_ic kich1 kI ins char/enter ins mode key에 의해 보내진다
key_il kil1 kA insert line에 의해 보내진다
key_left kcub1 kl terminal left arrow key에 의해 보내진다
key_ll kll kH home-down key에 의해 보내진다 key_mark kmrk %2 mark key
key_message kmsg %3 message key
key_move kmov %4 move key
key_next knxt %5 next key
key_npage knp kN next-page key에 의해 보내진다
key_open kopn %6 open key
key_options kopt %7 options key
key_ppage kpp %8 previous key
key_print kprt %9 print key
key_redo krdo %0 redo key
key_reference kref &1 reference key
key_refresh krfr &2 refresh key
key_replace krpl &3 replace key
key_restart krst &4 restart key
key_resume kres &5 resume key
key_right kcuf1 kr terminal right arrow key에 의해 보내진다
key_save ksav &6 save key
key_sbeg kBEG &9 shifted begin key
key_scancel kCAN &0 shifted cancel key
key_scommand kCMD *1 shifted command key
key_scopy kCPY *2 shifted copy key
key_screate kCRT *3 shifted create key
key_sdc kDC *4 shifted delete char key
key_sdl kDL *5 shifted delete line key
key_select kslt *6 select key
key_send kEND *7 shifted end key
key_seol kEOL *8 shifted end of line key
key_sexit kEXT *9 shifted exit key
key_sf kind kF Sent by scroll-forward/down key
key_sfind kFND *0 shifted find key
key_shelp kHLP #1 shifted help key
key_shome kHOM #2 shifted home key
key_sic kIC #3 shifted insert char key
key_sleft kLFT #4 shifted left key
key_smessage kMSG %a shifted message key
key_smove kMOV %b shifted move key
key_snext kNXT %c shifted next key
key_soptions kOPT %d shifted options key
key_sprevious kPRV %e shifted previous key
key_sprint kPRT %f shifted print key
key_sr kri kR scroll-backward/up key에 의해 보내진다
key_sredo kRDO %g shifted redo key
key_sreplace kRPL %h shifted replace key
key_sright kRIT %i shifted right key
key_srsume kRES %j shifted resume key
key_ssave kSAV !1 shifted save key
key_ssuspend kSPD !2 shifted suspend key
key_stab khts kT Sent by set-tab key
key_sundo kUND !3 shifted undo key
key_suspend kspd &7 suspend key
key_undo kund &8 undo key
key_up kcuu1 ku terminal up arrow key에 의해 보내진다
keypad_local rmkx ke Out of "keypad transmit" mode
keypad_xmit smkx ks Put terminal in "keypad transmit" mode
lab_f0 lf0 l0 Labels on function key f0 if not f0
lab_f1 lf1 l1 Labels on function key f1 if not f1
lab_f2 lf2 l2 Labels on function key f2 if not f2
lab_f3 lf3 l3 Labels on function key f3 if not f3
lab_f4 lf4 l4 Labels on function key f4 if not f4
lab_f5 lf5 l5 Labels on function key f5 if not f5
lab_f6 lf6 l6 Labels on function key f6 if not f6
lab_f7 lf7 l7 Labels on function key f7 if not f7
lab_f8 lf8 l8 Labels on function key f8 if not f8
lab_f9 lf9 l9 Labels on function key f9 if not f9
lab_f10 lf10 la Labels on function key f10 if not f10
label_on smln LO soft labels로 전환한다
label_off rmln LF soft labels를 해지한다
meta_off rmm mo "meta mode"를 해지한다
meta_on smm mm "meta mode" (8th bit)로 전환한다
micro_column_address mhpa ZY Like column_address for micro adjustment
micro_down mcud1 ZZ Like cursor_down for micro adjustment
micro_left mcub1 Za Like cursor_left for micro adjustment
micro_right mcuf1 Zb Like cursor_right for micro adjustment
micro_row_address mvpa Zc Like row_address for micro adjustment
micro_up mcuu1 Zd Like cursor_up for micro adjustment
newline nel nw Newline (lf에 의해 따라오는 cr과 같이 행동한다)
order_of_pins porder Ze Matches software buts to print-head pins
orig_colors oc oc 모든 색상 쌍들을 Reset한다
orig_pair op op 원래의 것으로 디폴트 색상-쌍을 지정한다
pad_char pad pc Pad character (rather than null)
parm_dch dch DC #1 chars (PG*)를 지운다
parm_delete_line dl DL #1 lines (PG*)을 지운다
parm_down_cursor cud DO 커서를 #1 lines (PG*) 아래로 이동시킨다
parm_down_micro mcud Zf Like cud for micro adjust
parm_ich ich IC #1 blank chars (PG*)를 삽입한다
parm_index indn SF 앞으로 #1 lines (PG)을 스크롤한다
parm_insert_line il AL #1 new blank lines (PG*)을 더한다
parm_left_cursor cub LE 커서를 왼쪽으로 #1 spaces (PG)만큼 이동시킨다
parm_left_micro mcub Zg Like cul for micro adjust
parm_right_cursor cuf RI 커서를 오른쪽으로 #1 spaces (PG*)만큼 이동시킨다
parm_right_micro mcuf Zh Like cuf for micro adjust
parm_rindex rin SR 뒤로 #1 lines (PG)만큼 스크롤한다
parm_up_cursor cuu UP 커서를 위로 #1 lines (PG*)만큼 이동시킨다
parm_up_micro mcuu Zi Like cuu for micro adjust
pkey_key pfkey pk Prog funct key #1 to type string #2
pkey_local pfloc pl Prog funct key #1 to execute string #2
pkey_xmit pfx px Prog funct key #1 to xmit string #2
pkey_plab pfxl xl Program key #1 to xmit #2 and show #3
plab_norm pln pn program label #1 to show string #2
print_screen mc0 ps 화면의 내용을 인쇄한다
prtr_non mc5p pO Turn on the printer for #1 bytes
prtr_off mc4 pf 프린터를 끈다
prtr_on mc5 po 프린터를 켠다
repeat_char rep rp 문자를 #1 #2 times 반복한다. (PG*)
req_for_input rfi RF 입역을 위해 요청한다
reset_1string rs1 r1 Reset terminal completely to sane modes.
reset_2string rs2 r2 Reset terminal completely to sane modes.
reset_3string rs3 r3 Reset terminal completely to sane modes.
reset_file rf rf reset 문자열을 포함하고 있는 파일의 이름
restore_cursor rc rc 마지막 sc의 위치로 커서를 재저장한다
row_address vpa cv Vertical position absolute (set row) (PG)
save_cursor sc sc 커서의 위치를 저장한다(P)
scancode_escape scesc S7 Escape for scancode emulation
scroll_forward ind sf 텍스트를 위로 스크롤한다 (P)
scroll_reverse ri sr 텍스트를 아래로 스크롤한다 (P)
select_char_set scs Zj 문자 집합을 선택한다
set0_des_seq s0ds s0 Shift to codeset 0 (EUC set 0, ASCII)
set1_des_seq s1ds s1 Shift to codeset 1
set2_des_seq s2ds s2 Shift to codeset 2
set3_des_seq s3ds s3 Shift to codeset 3
set_a_background setab AB ANSI escape를 사용하는 background 색상을 지정한다
set_a_foreground setaf AF ANSI escape를 사용하는 foreground 색상을 지정한다
set_attributes sgr sa 비디오 속성을 정의한다(PG9)
set_background setb Sb 현재 background 색상을 지정한다
set_bottom_margin smgb Zk 현재 줄의 아래 여백(bottom margin)을 지정한다
set_bottom_margin_parm smgbp Zl 바닥으로 부터 at line #1 or #2 lines에 바닥 줄을 지정한다
set_color_band setcolor Yz 리본 색상을 #1로 바꾼다
set_color_pair scp sp 현재의 색상 쌍을 지정한다
set_foreground setf Sf 현재의 foreground 색상을 지정한다
set_left_margin smgl ML 현재 줄에 왼쪽 여백(left margin)을 지정한다
set_left_margin_parm smglp Zm #1 (#2)에 왼쪽(오른쪽)여백을 지정한다
set_lr_margin smglr ML 왼쪽과 오른쪽 여백 모두를 지정한다
set_page_length slines YZ 페이지의 길이를 #1 lines로 지정한다 (tparm 사용)
set_right_margin smgr MR 현재의 컬럼에 오른쪽 여백을 지정한다
set_right_margin_parm smgrp Zn 컬럼 #1에 오른쪽 여백을 지정한다
set_tab hts st 모든 row의 현재 컬럼에 tab을 지정한다
set_tb_margin smgtb MT 위와 아래 여백 모두를 지정한다
set_top_margin smgt Zo 현재 줄에 위쪽 여백을 지정한다
set_top_margin_parm smgtp Zp line #1에 위 여백을 지정한다
set_window wind wi 현재의 윈도우는 lines #1-#2 cols #3-#4이다
start_bit_image sbim Zq bit image graphics 인쇄를 시작한다
start_char_set_def scsd Zr 문자 집합의 정의를 시작한다
stop_bit_image rbim Zs bit image graphics 인쇄를 끝낸다
stop_char_set_def rcsd Zt 문자 집합 정의를 끝낸다
subscript_characters subcs Zu subscriptable 문자들의 목록
superscript_characters supcs Zv superscriptable 문자들의 목록
tab ht ta Tab to next 8 space hardware tab stop
these_cause_cr docr Zw 이러한 문자들은 CR을 야기시킨다
to_status_line tsl ts 상태줄의 column #1로 간다
underline_char uc uc Underscore one char and move past it
up_half_line hu hu Half-line up (reverse 1/2 linefeed)
xoff_character xoffc XF XON character
xon_character xonc XN XOFF character
(다음의 문자열 능력들은 SYSVr 용어 구조 안에 표현되지만 man page안에는 문서화되어 있지 않다. 주석들은 용어 구조 헤더에 있다.) label_format fln Lf ??
set_clock sclk SC time-of-day 시계를 지정한다
display_clock dclk DK time-of-day 시계를 표시한다
remove_clock rmclk RC time-of-day 시계를 제거한다??
create_window cwin CW Define win #1 to go from #2,#3 to #4,#5
goto_window wingo WG 윈도우 #1로 간다
hangup hup HU Hang up phone
dial_phone dial DI Dial phone number #1
quick_dial qdial QD Dial phone number #1, without progress detection
tone tone TO touch tone dialing을 선택한다
pulse pulse PU pulse dialing을 선택한다
flash_hook hook fh Flash the switch hook
fixed_pause pause PA 2 ~ 3초간 정지한다
wait_tone wait WA Wait for dial tone
user0 u0 u0 사용자 문자열 # 0
user1 u1 u1 사용자 문자열 # 1
user2 u2 u2 사용자 문자열 # 2
user3 u3 u3 사용자 문자열 # 3
user4 u4 u4 사용자 문자열 # 4
user5 u5 u5 사용자 문자열 # 5
user6 u6 u6 사용자 문자열 # 6
user7 u7 u7 사용자 문자열 # 7
user8 u8 u8 사용자 문자열 # 8
user9 u9 u9 사용자 문자열 # 9
get_mouse getm Gm Curses 버튼 이벤트를 가져야만 한다
key_mouse kmous Km ??
mouse_info minfo Mi 마우스 상태 정보
pc_term_options pctrm S6 PC 단말기 선택사항
req_mouse_pos reqmp RQ 마우스 위치에 대한 보고를 요청한다
zero_motion zerom Zx 뒤따라오는 문자를 위한 움직임은 없다
8.23 [N]Curses 함수 개관 ([N]Curses Function Overview)
다음의 텍스트에서 다른 (n)curses 패키지를 통한 개요(overview)를 찾을 수 있을 것이다. 첫번째 컬럼은 bsd-curses이고(슬랙웨어 2.1.0과 Sun-OS 4.x에서 처럼) 두번째는 sysv-curses (Sun-OS 5.4/Solaris 2)이고 세번째는 ncurses(버전 1.8.6)이다.
네번째는 함수가 (실제로 설명되어있다면) 설명되어있는 텍스트의 페이지를 참조한다.
- x
- 패키지는 이 함수를 가진다.
- n
- 함수는 아직 구현되지 않음.
계속......
int main()
{
int shmid;
char *shared_memory;
shmid = shmget(7530, 1028, IPC_CREAT|0666);
shared_memory = shmat(shmid, NULL, 0);
printf("talk is : %s\n", shared_memory);
return 0;
}
리눅스용으로 만들어진 소스구요..
주석좀 자세히 알려주시면 감사하겠습니다.
shmget,shmat에 관해서 자세히 설명해주시고요.
공유메모리 관련이라고 하는데 도저히 설명을 못찾아서 여기 올립니다.
< 답 변 >
shmat, shmget 는 공유 메모리 관련 함수 입니다.
이 함수들은 서로 다른 Process 들끼리 공통으로 사용할 수 있는 메모리를
지원합니다.
shmget 는 메모리를 할당하는 역할을 하고
shmat 는 할당된 메모리를 시스템이 공통으로 사용할 수 있는 영역에 붙이는 작업을 합니다.
일반적으로 사용하는 방법은 이렇게 사용하는 것 보다 다르게 사용 합니다.
1. 파일 Open (open 사용)
2. 파일 메모리 할당 (mmap 사용)
3. 파일 핸들을 공유 메모리영역에 할당 (shmat 사용)
차례로 설명하겠습니다.
1번에서는 open 함수를 써서 파일을 open 합니다.
2 번에서는 파일의 모든 내용을 읽어오기 위해서 mmap 함수를 써서 파일의
모든 내용을 메모리와 동기화 합니다.
mmap 함수는 파일과 메모리를 서로 동기화하여 파일을 write 할 때도 메모리에
write 하는 것 처럼 사용하고, 시스템에서는 메모리와 파일을 동기화 작업을 합니다.
하지만 동기화는 자주 일어나는 것이 아니기 때문에 아주 정확한 데이터가 파일에
저장되길 원하면 msync 함수를 써서 일정 시간마다 동기화 합니다.
참, mmap 함수를 사용할 때 SHM_MAP 을 꼭 사용하여야 나중에 다른 프로세서와
공유가능 합니다.
3번에서는 1번에서 사용한 핸들을 공유메모리에 붙입니다. 그러면 open 한 파일은
특정 프로세서를 기준으로 보면
1. 파일과 메모리
2. 파일과 메모리, Shared 메모리
와 모두 동기화 됩니다.
물론 다른 프로세서에서도 동일한 작업을 하게 됩니다. 그러면 다른 프로세서에서도
3. 파일과 메모리, Shared 메모리, 타 프로세서에서의 동기화가 모두 이루어 집니다.
이것의 장점은 데이터의 크기가 큰 것들을 다른 프로세서와 모두 동기화가 가능하다
는 것 입니다.
그리고 속도도 어떤 것 들보다 빠릅니다.
일반적으로 프로세서와의 통신은
메시지큐, FIFO, 파이프, 소켓등이 있습니다만 이것만큼 빠르게 큰 데이터를 공유할
있는 것이 없을 겁니다.
아주 좋은 것들이니 잘 익혀서 사용하시면 좋을 것 같군요 ....
도움이 도시길 ....
1장. shmget(2)
공유메모리 영역을 할당한다.
1.2. 설명
shmget()은 주어진 인자 key를 접근번호로 하는 공유메모리 공간할당을 커널에 요청한다. 커널에서 성공적으로 공유메모리 공간을 할당하게 되면 공유메모리를 가르키는 식별자를 리턴하게 된다. 생성될 공유메모리 공간의 크기는 size를 통해서 byte 단위 크기로 지정할 수 있다. 공간의 할당은 shmflg가 IPC_PRIVATE이거나 key 를 가지는 공유메모리영역이 존재하지 않거나, IPC_CREAT가 지정되었을 경우 (shmflg&IPC_CREAT가 0이 아닌)에 이루어진다.
다음은 사용가능한 shmflg값들이다.
- IPC_CREAT
-
새로운 영역을 할당한다. 만약 이 값이 사용되지 않았다면, shmget()은 key로 이미 생성된 접근 가능한 공유메모리 영역이 있는지 확인하고 이에 대한 식별자를 되돌려줄 것이다.
- IPC_EXCL
-
IPC_CREAT와 함께 사용하며 공유메모리 영역이 이미 존재하면 에러를 리턴한다.
- mode_flags(하위 9bit)
-
접근 권한의 지정을 위해서 사용한다. 실행권한은 사용하지 않는다.
만약 새로운 영역이 생성되었다면 shmflg의 권한정보는 영역에 대한 정보가 정의되어 있는 shmid_ds 구조체의 멤버인 shm_perm으로 복사된다. shmid_ds 구조체는 아래와 같이 정의되어 있다.
struct shmid_ds { |
1.5. 에러
- EINVAL
-
공유 영역생성시 너무 작은 공간을 할당 하거나(size < SHMMIN) 너무 큰 공간(size > SHMMAX)을 할당했을 경우
- EEXIST
-
- EACCESS
-
IPC_CREAT | IPC_EXCL 로 생성을 요청했는데, 이미 공유 메모리 영역이 존재하고 있을 경우,
- ENOSPC
-
size만큼의 공간을 할당할 수 없을 경우. 사용가능한 공간은 SHMALL값으로 커널전역적으로 정의되어 있다. (/usr/include/linux/shm.h 참고)
- ENOENT
-
IPC_CREAT를 사용하지 않았는데, 해당 key를 가지는 공유 메모리 영역이 존재 하지 않는 경우
- EACCESS
-
공유 메모리 영역에 대한 접근권한이 주어져 있지 않다.
- ENOMEM
-
이용할 수 있는 커널 메모리가 충분하지 않다.
1.7. 참고문헌
1장. shmat(2)
공유메모리 관련 연산
1.1. 사용법
#include <sys/ipc.h> |
1.2. 설명
shmat()는 공유메모리 식별자인shmid에 공유 메모리 세그먼트를 붙이기 위해서 사용한다. 붙이는 영역은 shmaddr로 결정할 수 있다.
만약 shmaddr가 NULL이라면 시스템은 적당한 사용하지 않는 메모리 영역을 붙이게 된다.
만약 shmaddr가 NULL이 아니고 SHM_RND가 shmflg로 지정되어 있다면 shmaddr은 SHMLBA의 배수의 주소로 연결이 발생한다. 그렇지 않으면 shmaddr은 연결할 수 있는 정렬된 페이지 주소여야 한다.
만일 SHM_RDONLY가 shmflg에 지정되었다면, 세그먼트는 읽기전용이 되며 공유메모리 영역에 접근하고자 하는 프로세스는 읽기전용허가 접근권을 가져야 한다. 그렇지 않을경우 세그먼트는 읽기/쓰기로 붙여지며 프로세스는 (반드시)읽기/쓰기 허가권을 가져야한다. 쓰기전용 공유메모리 세그먼트를 위한 플래그는 없다.
프로세스가 종료되면 연결된 세그먼트는 자동적으로 분리된다. 동일한 세그먼트는 읽기와 읽기/쓰기로 한번이상 연결시킬 수 있다.
shmat가 성공하면 시스템은 shmid_ds구조체의 멤버들을 아래와 같이 업데이트 시킨다.
-
shm_atime을 현재 시간으로 수정한다.
-
shm_lpid를 현재 호출한 프로세스의 ID로 설정한다.
-
shm_nattch는 1 증가 시킨다.
공유메모리 세그먼트가 삭제로 표시될 때에도 마찬가지로 분리된다.
shmdt()는 공유 메모리 영역으로 부터 shmaddr 주쇼를 분리 시키기 위해서 사용한다. 공유메모리 영역의 분리는 shmat 시스템 콜로 연결된 값과 동일한 shmaddr을 가지고 있는 연결된 영역들중 하나여야 한다.
shmdt()가 성공적으로 호출되면 shmid_ds구조체의 멤버를 다음과 같이 변경한다.
-
shm_dtime을 현재 시간으로 변경한다.
-
shm_lpid를 현재 호출한 프로세스의 ID로 변경한다.
-
shm_nattch을 1 감소 시킨다. 만약 값이 0이되고 세그먼트에 삭제표시가 되어 있다면 세그먼트는 삭제된다.
1.4. 에러
- EACCES
-
호출한 프로세스가 붙이기 원하는 영역에 대해서 권한을 가지고 있지 않다.
- EINVAL
-
잘못된 shmid 값, 혹은 잘못된 shmaddr 값을 가지고 있다.
- ENOMEM
-
메모리할당을 할 수 없다.
1.5. 예제
#include <sys/ipc.h> |
1.6. 참고문헌
이 문서는 수정될 수 있습니다. 최신문서는 Joinc Wiki에서
'About 배우고 익히는법 > 펌글' 카테고리의 다른 글
Linux] NCURSES란 ? (0) | 2013.12.31 |
---|---|
[Linux] NCURSES 프로그래밍 (0) | 2013.12.31 |
[Linux] shmget - 공유메모리 영역을 할당 (0) | 2013.12.31 |
[Linux] Charater Cell Graphics (0) | 2013.12.31 |
[Linux] NCURSES Programming HOWTO (0) | 2013.12.31 |