09
5月
2007

terminfo

terminfoを使用すると出力場所とかをイイ感じにできるかもしれない.
terminfoとは
terminfoのデータ
clear
カーソル移動

terminfoとは

かつてのUNIXシステムではいろんな端末があって,それらの制御方法は標準化されていなかった.そこで,統一されたインタフェースでプログラムからの要求を受け取り,保持している各端末の制御方法に関するデータを参照して処理するパッケージとしてterminfoが登場した.terminfoはcursesと組み合わせて使用するが,両者の境界はなんだかあいまいらしい.

terminfoのデータ

私のシステムではterminfoのデータが入っているterminfoファイルは/usr/share/terminfo/に沢山あった.これらはterminfoファイル名の頭文字ごとにディレクトリに分けられ,それぞれのterminfoファイルはticというコマンドでコンパイルされたもの(バイナリファイル)らしい.terminfoファイル内の各データは以下の3種類に分けられる.
ブール型
該当する機能をサポートするか否か.
数値型
サイズを表す.
文字列型
端末機能にアクセスするためのキーとか,キーボード入力をどんな文字列に変換してプログラムに渡すかを定義.
端末を制御するコーディングの流れは大体以下のようになる.
setuptermで現在の端末に対応するTERMINAL構造体を取得
tigetflag,tigetnum,tigetstrで現在の端末の状態を取得
エスケープシーケンスを生成
putp,tputsでエスケープシーケンスを端末に送る
エスケープシーケンスの生成についてちょっと書いておく.まず,どんな文字列型のデータがあるかは,man 5 terminfoに一覧がある(やたら多い).ここにある「Capname」をキーにしてtigetstrを呼び出すとその機能に対応したエスケープシーケンスが得られる.で,そこで得られるエスケープシーケンスの中にはそのままでは使用できないものがある.「カーソルを何行目の何列目に移動しろ」などという命令に対応するエスケープシーケンスは,数が膨大になるのを防ぐために,「何行目」とか「何列目」というのをパラメータ化している.このような場合,tparmを使用して取得したエスケープシーケンスのパラメータに具体的な値をいれるというステップが入る.

clear

サンプルとしてclearコマンドを作成する.man clearによるとclearコマンド自体,tputをclear引数とともに呼んでいるらしい.

#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <term.h>

int main(void)
{
  char *clear_cmd;

  /* setupterm�ϼ��Ԥ���ȥ��顼���Ǥ��ƽ�λ���뤬
     ����񤤤Ȥ� */
  if(setupterm(NULL, fileno(stdout), NULL) == ERR){
    exit(EXIT_FAILURE);
  }

  /* clear���뤿��Υ��������ץ������󥹤���� */
  clear_cmd = tigetstr("clear");
  if(clear_cmd == (char *)-1 ||
     clear_cmd == (char *)0){
    exit(EXIT_FAILURE);
  }

  /* �����������������ץ������󥹤�ü�������� */
  tputs(clear_cmd, 1, putchar);

  exit(EXIT_SUCCESS);
}

terminfoを使用するときは,コンパイル時にコンパイルオプションが必要である.私のシステムでは以下でコンパイルできた.
gcc -Wall -o my_clear my_clear.c -lncurses
-lncursesがないと怒られる.システムによっては-Iでncurses.hの場所を教える必要があるかもしれない(私のシステムでは/usr/include/ncurses.hがあった).コンパイル後実行するとclearコマンドと同様の結果が得られた.

カーソル移動

もう一つの例としてカーソル移動のサンプルを作成してみた.

#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <term.h>
#include <curses.h>
#include <errno.h>

/* �󥫥Υ˥���⡼�ɤˤ��� */
int to_nocanon(void);
/* ���������ư���� */
int mv_cursor(void);

static struct termios save_term;
static struct termios temp_term;

int main(void)
{
  char *cmd;
  int result;

  /* ���åȥ��å� */
  if(setupterm(NULL, fileno(stdout), (int *)0) == ERR){
    fprintf(stderr,"setupterm failure\n");
    exit(EXIT_FAILURE);
  }

  /* clear���� */
  errno = 0;
  if((cmd = tigetstr("clear")) == NULL){
    perror("tigetstr failure");
    exit(EXIT_FAILURE);
  }
  if(putp(cmd) == ERR){
    exit(EXIT_FAILURE);
  }

  /* �󥫥Υ˥���⡼�ɤˤ��� */
  if(to_nocanon() == -1){
    exit(EXIT_FAILURE);
  }

  /* ���Ϥ˱����ƥ��������ư���� */
  while(1){
    if((result = mv_cursor()) == -1){
      tcsetattr(fileno(stdin), TCSANOW, &save_term);
      exit(EXIT_FAILURE);
    }else if(result == 1){
      break;
    }
  }

  /* ���Υ˥���⡼�ɤ��᤹ */
  tcsetattr(fileno(stdin), TCSANOW, &save_term);
  exit(EXIT_SUCCESS);
}

/* �󥫥Υ˥���⡼�ɤˤ��� */
int to_nocanon(void)
{
  errno = 0;
  if(tcgetattr(fileno(stdin), &save_term) == -1){
    perror("tcgetattr failure");
    exit(EXIT_FAILURE);
  }else{
    temp_term = save_term;
  }
  temp_term.c_iflag &= IGNCR;
  temp_term.c_oflag &= ONLRET;
  temp_term.c_lflag &= (~ISIG & ~ICANON & ~ECHO);
  temp_term.c_cc[VMIN] = 1;
  temp_term.c_cc[VTIME] = 5;

  errno = 0;
  if(tcsetattr(fileno(stdin), TCSANOW, &temp_term) == -1){
    perror("tcsetattr failure");
    return -1;
  }
  return 0;
}

/* ���������ư���� */
int mv_cursor(void)
{
  char ch;
  char *cmd;

  ch = getchar();
  switch(ch){
  default:
    return 0;
    break;
  case 'q':
    return 1;
    break;
  case 'h':
    /* ���������1��� */
    cmd = tigetstr("cub1");
    break;
  case 'j':
    /* ���������1�IJ��� */
    cmd = tigetstr("cud1");
    break;
  case 'k':
    /* ���������1�ľ�� */
    cmd = tigetstr("cuu1");
    break;
  case 'l':
    /* ���������1�ı��� */
    cmd = tigetstr("cuf1");
    break;
  }

  if(cmd == NULL){
    fprintf(stderr, "cmd == NULL\n");
    return -1;
  }else if(putp(cmd) == ERR){
    fprintf(stderr, "putp failure\n");
    return -1;
  }
  return 0;
}

このサンプルはviみたくhjklでカーソルを移動する.文字は入力できない.あとqを入力すると終了する.

You may also like...