Display (2)

make cscope

FreeBSDの/sysにあるMakefileに面白い記述を発見。

# You need the devel/cscope port for this.
cscope: cscope.out
cscope.out: ${.CURDIR}/cscope.files
        cd ${.CURDIR}; cscope -k -buq -p4 -v

cscope用のDBを作ってくれるとな。それからglobalを入れておくとTAGSも作成してくれるよ。

root@fb:/sys # make TAGS
cd /usr/src/sys;  find bsm cam cddl compat conf contrib crypto ddb dev fs gdb  geom gnu isa kern libkern modules net net80211  netgraph netinet netinet6 netipsec netpfil  netsmb nfs nfsclient nfsserver nlm ofed opencrypto  rpc security sys ufs vm xdr xen i386 x86 -name "*.[chSsly]" -a -type f > /usr/src/sys/cscope.files
rm -f /usr/src/sys/TAGS
cd /usr/src/sys; xargs etags -a < /usr/src/sys/cscope.files

これだけで、ソースの海をスイスイと泳ぎ回れるとな。追加分は次の通り。

[sakae@fb /sys]$ ls -lh cscope.* TAGS
-rw-r--r--  1 root  wheel    48M Sep 11 07:43 TAGS
-rw-r--r--  1 root  wheel   354K Sep 11 07:43 cscope.files
-rw-r--r--  1 root  wheel    33M Sep 11 06:00 cscope.in.out
-rw-r--r--  1 root  wheel   172M Sep 11 06:00 cscope.out
-rw-r--r--  1 root  wheel   113M Sep 11 06:00 cscope.po.out

漢字ROM (bdf font)

漢字が表示出来るフォントに出会ったので、少しその方面を調べてみる。

BDF形式

Glyph Bitmap Distribution Format

[sakae@fb /usr/src/X11/font/adobe-100dpi]$ lv timR24.bdf
STARTFONT 2.1
FONT -Adobe-Times-Medium-R-Normal--34-240-100-100-P-170-ISO10646-1
SIZE 24 100 100
FONTBOUNDINGBOX 38 48 -5 -11
  :
STARTCHAR three
ENCODING 51
SWIDTH 500 0
DWIDTH 16 0
BBX 12 23 2 0
BITMAP
0F80
3FC0
 :
7F00
ENDCHAR

ISO10646と言うのはユニコードなんだな。FreeBSDのコンソールでは、このタイプのフォントをvtfontcvtっていうアプリで、*.fntって形式に変換して使ってる。

bdf to (fnt|pcf)

FreeBSDのvtコンソールが扱かうフォント形式は特殊だ。そのためフォントのソースであるBDF形式を変換する必要がある。

[sakae@fb /usr/src/X11/font]$ cp sony-misc/8x16.bdf /tmp/
[sakae@fb /tmp]$ vtfontcvt -v 8x16.bdf aa.fnt
Statistics:
- width:                            8
- height:                          16
- glyph_total:                    190
- glyph_normal:                   190
- glyph_normal_right:               0
- glyph_bold:                       0
- glyph_bold_right:                 0
- glyph_unique:                   190
- glyph_dupe:                       0
- mapping_total:                  190
- mapping_normal:                 190
- mapping_normal_folded:            2
- mapping_normal_right:             0
- mapping_normal_right_folded:      0
- mapping_bold:                     0
- mapping_bold_folded:              0
- mapping_bold_right:               0
- mapping_bold_right_folded:        0
- mapping_unique:                 190
- mapping_dupe:                     0

約30Kあったものが3kのサイズに変換された。それだけじゃなくて、マシンが扱い易い形式になっているんだろうね。

上記はFreeBSDに特有な事情だったけど、Xorg界では、 ports/x11-fonts/bdftopcf と言うフォントのコンパイラーが用意されてる。これを使うとフォントのソース(BDF)をXが普通に使うPortable Compiled Format (PCF) に変換出来る。 当然、逆コンパイラーも用意されてて、改変が出来る。

X11 の PCF ビットマップフォントファイルのフォーマット にあるように、バイナリーな形式のやつは、フォーマットがグチャグチャしてて、そのままでは容易に扱える代物では無い。

vt100

軽くフォントの事を調べてみたけど、以前にやったminixでは、フォントの話なんてさっぱり出てこなかったぞ。それにも拘わらず、ちゃんと表示出来てるって事は、ターミナル自身にフォントを内蔵してるはず。本当かどうかターミナルの元祖vt100に当ってみる。

VT100 Programmer Information

G0 Sets Sequence 	G1 Sets Sequence 	Meaning
ESC ( A 	ESC ) A 	United Kingdom Set
ESC ( B 	ESC ) B 	ASCII Set
ESC ( 0 	ESC ) 0 	Special Graphics
ESC ( 1 	ESC ) 1 	Alternate Character ROM Standard Character Set
ESC ( 2 	ESC ) 2 	Alternate Character ROM Special Graphics

やっぱりROMが内蔵されてた。そしてその切り換えは、得意のエスケープシーケンスで行うとな。英米の切り換えが可能。

console of ArchLinux

ちょっと更新をサボっていたら、500Mぐらい、新しいのがきた。そして、少しづつ肥大化してる。で、コンソール系はどうなってるか調べてみた。

Linux コンソール なかなか良い起点を示してくれている。

Arch Linuxのコンソールで日本語環境を作る 検索に引掛ったもの

Linux framebuffer 現代風なコンソールの土台

Text mode 古風なモード

Code page 437 IBM PCのセミ・グラフィック仕様

svgalib to SDL2

Welcome to SVGAlib こんな、画面に向ってのお絵描き例が出てた。

#include <stdlib.h>
#include <unistd.h>
#include <vga.h>

int main(void) {
   int color = 4;
   int x = 10;
   int y = 10;
   unsigned int seconds = 5;

   /* detect the chipset and give up supervisor rights */
   if (vga_init() < 0)
        return EXIT_FAILURE;

   vga_setmode(G320x200x256);
   vga_setcolor(color);
   vga_drawpixel(x, y);

   sleep(seconds);

   /* restore textmode and fall back to ordinary text console handling */
   vga_setmode(TEXT);

   return EXIT_SUCCESS;
}

コンパイルと実行は

[sakae@fb /tmp]$ cc -I/usr/local/include -L/usr/local/lib s.c -lvga
[sakae@fb /tmp]$ chmod u+s a.out
[sakae@fb /tmp]$ ./a.out
svgalib: Cannot get I/O permissions.

何処で文句を言われるかと調べたら、 vga_init の所だった。ポートになってるぐらいだから、動いてもよさそう。ひょっとして、FreeBSDでもLinuxのふりをする環境にしないと駄目なのかな?

Why does a programs terminate immediatelly with "svgalib: Cannot get I/O permissions."?

svgalib programs need to be run as root. This means that either the user that runs them is root, 
or, if running by normal users is desirable, the program needs to be 'suid root', 
which means: the program must be owned by root (chown 0 program) and the suid bit needs to be set (chmod u+s program). 

例によって、役にたたないFAQであります。ソース嫁が一番のFAQでしょう。

じゃ、Debianではどうか? パッケージになっていない。いやな予感。ソースからコンパイルしたらボロボロとエラーになって取り付く島もない。ArchLinuxは? やっぱり入っていない。過去の遺物なんだな。見きりをつけよう。

代わりは、SDL Language Bindings こんなのかな? ちょっと違う気がしないでもないな。

Hello SDL: Your First Graphics Window

[sakae@fb /tmp/01_hello_SDL]$ cc 01_hello_SDL.cpp -I/usr/local/include/SDL2 -L/usr/local/lib -lSDL2
[sakae@fb /tmp/01_hello_SDL]$ ls -l
total 24
-rwxr-x---  1 sakae  wheel   1304 Mar 14 13:54 01_hello_SDL.cpp*
-rwxr-xr-x  1 sakae  wheel  13364 Sep 11 16:12 a.out*
-rwxr-x---  1 sakae  wheel    286 Mar 14 13:54 readme.txt*

Simple DirectMedia Layer (man-jp)

vesa or vga

/sys/dev/fb/{vga,vesa}.[ch] なんてのが有って、そこでsplashしてるみたい。つらつら見ていくと、どうやらBIOSからのサポートがあるみたいだ。そんなわけで、資料収集。

シンプルビデオドライバ

ドライバーその他 グラフィックドライバー

Tips VESA VBE仕様

VMWARE 仮想ハードウェアの仕様

今更、こういう趣味に走る人は少ないので、余り出てこない。

putty

ひょんな事からputtyがUNIXでもサポートされてる事を知った。今迄Windows専用とばかり思っていたぞ。恥しい事だ。

putty-0.77 にソースやら実行形式が置いてある。確かにWindowsに傾いてはいるけどね。 んな訳で、ソースを紐解いてみる。

GUIなアプリなんで、使って天国、作るのは地獄。ついでに見るのも地獄ですよ。発散しないように注意。ターミナルってdirの中だけを干渉、もとえ鑑賞する。

まずはお約束で、terminal.h から。GUIな作者にみられるような、横幅がビローンとのび太コードになっていない。80桁にコードが収まるように、極力配慮されてる。こうでなくちゃね。 コメントがしっかり入ているので、余生を送るには最適と思うぞ。まあ、先に意気ますか。

terminal.c

/*
 * Terminal emulator.
 */

#define CL_ANSIMIN      0x0001         /* Codes in all ANSI like terminals. */
#define CL_VT100        0x0002         /* VT100 */
#define CL_VT100AVO     0x0004         /* VT100 +AVO; 132x24 (not 132x14) & attrs */
#define CL_VT102        0x0008         /* VT102 */
#define CL_VT220        0x0010         /* VT220 */
#define CL_VT320        0x0020         /* VT320 */
#define CL_VT420        0x0040         /* VT420 */
#define CL_VT510        0x0080         /* VT510, NB VT510 includes ANSI */
#define CL_VT340TEXT    0x0100         /* VT340 extensions that appear in the VT420 */
#define CL_SCOANSI      0x1000         /* SCOANSI not in ANSIMIN. */
#define CL_ANSI         0x2000         /* ANSI ECMA-48 not in the VT100..VT420 */
#define CL_OTHER        0x4000         /* Others, Xterm, linux, putty, dunno, etc */

#define TM_VT100        (CL_ANSIMIN|CL_VT100)
#define TM_VT100AVO     (TM_VT100|CL_VT100AVO)
#define TM_VT102        (TM_VT100AVO|CL_VT102)
  :

色々な端末の真似をするやつだよってのが宣言されてる。 いかめしい定義の割りには、参照してる所が限定されてる。

/*
 * Remove everything currently in `inbuf' and stick it up on the
 * in-memory display. There's a big state machine in here to
 * process escape sequences...
 */
static void term_out(Terminal *term, bool called_from_term_data)
{
     :
            /*
             * If we're in print-only mode, we use a much simpler
             * state machine designed only to recognise the ESC[4i
             * termination sequence.
             */
            if (term->only_printing) {
                if (c == '\033')
                    term->print_state = 1;
                else if (c == (unsigned char)'\233')
                    term->print_state = 2;
                else if (c == '[' && term->print_state == 1)
                    term->print_state = 2;
                else if (c == '4' && term->print_state == 2)
                    term->print_state = 3;
                else if (c == 'i' && term->print_state == 3)
                    term->print_state = 4;
                else
                    term->print_state = 0;
                if (term->print_state == 4) {
                    term_print_finish(term);
                }
                continue;
            }

エスケープシーケンスを解読するルーチン。これと同じ方策のものがminixの所でも使われていたな。

ソースの冒頭で宣言されてた奴は、こんな風に使われていたぞ。

switch (term->esc_args[0]) {
  case 61:
    term->compatibility_level &= ~TM_VTXXX;
    term->compatibility_level |= TM_VT102;
    break;
  case 62:
    term->compatibility_level &= ~TM_VTXXX;
    term->compatibility_level |= TM_VT220;
    break;

色々な端末の真似をエスケープシーケンス等を考慮しながら行うってのは、無駄に大変と言う事が分った。心して利用しろとな。

苦労の跡は、これだけじゃない。同じ階層にbidi.cってファイルが有るんだけど、何者?って思って眺めてみたら、

/*
 * Implementation of the Unicode bidirectional and Arabic shaping
 * algorithms for PuTTY.
 *
 :

アラビア言語もサポートするっていう遠大なもの。まるでemacsとかrubyみたいに、色々な言語大好きさんでした。

一つ上の階層から辿れる、unix/window.cは

/*
 * window.c: the main code that runs a PuTTY terminal emulator and
 * backend in a GTK window.
 */

GTKの奧座敷で動くエミュレータの制御なんだね。6000行近いコード。これはこれで気違いじみているな(褒め言葉です)。

at minix

すっきりさっぱりのminixにおけるエスケープシーケンスを見て億。

PRIVATE out_char(tp, c)
register struct tty_struct *tp; /* pointer to tty struct */
char c;                         /* character to be output */
{
/* Output a character on the console. Check for escape sequences, including
 *   ESC 32+x 32+y to move cursor to (x, y)
 *   ESC ~ 0       to clear from cursor to end of screen
 *   ESC ~ 1       to reverse scroll the screen 1 line
 *   ESC z x       to set the attribute byte to x (z is a literal here)
 */

  /* Check to see if we are part way through an escape sequence. */
  if (tp->tty_esc_state == 1) {
        tp->tty_echar = c;
        tp->tty_esc_state = 2;
        return;
  }

  if (tp->tty_esc_state == 2) {
        escape(tp, tp->tty_echar, c);
        tp->tty_esc_state = 0;
        return;
  }
  :
  switch(c) {
        :
        case 033:               /* ESC - start of an escape sequence */
                flush(tp);      /* print any chars queued for output */
                tp->tty_esc_state = 1;  /* mark ESC as seen */
                return;
        :

出力ルーチンの中でシーケンスを見つけ出した場合、それを溜め込む。そして、溜った所で処理ルーチンを呼び出す。

PRIVATE escape(tp, x, y)
register struct tty_struct *tp; /* pointer to tty struct */
char x;                         /* escape sequence is ESC x y; this is x */
char y;                         /* escape sequence is ESC x y; this is y */
{
/* Handle an escape sequence. */

  int n, ct, vx;

  /* Check for ESC z attribute - used to change attribute byte. */
  if (x == 'z') {
        /* Set attribute byte */
        tp->tty_attribute = y << 8;
        return;
  }
  /* Check for ESC ~ n -  used for clear screen, reverse scroll. */
  if (x == '~') {
        if (y == '0') {
                /* Clear from cursor to end of screen */
         :

シーケンス長が固定なので、すっきりしてる。実務のやつは、長さもまちまちだし、機能も色々なので、こんなものでは済まない。

minix app

カーネルで定義されたエスケープシーケンスをminixのアプリが使っているはず。探してみたら、mined1.cに見付かった。minix流のemacs似のscreen editorらしい。

/* Escape sequences. */
#ifdef UNIX
char *CE, *VS, *SO, *SE, *CL, *AL, *CM;
#else
char   *enter_string = "\033 8\033~0";  /* String printed on entering mined */
char   *pos_string = "\033";            /* Absolute cursor position */
char   *rev_scroll = "\033~1";          /* String for reverse scrolling */
char   *rev_video = "\033z\160";        /* String for starting reverse video */
char   *normal_video = "\033z\007";     /* String for leaving reverse video */
#endif UNIX

mined2.cも見ておくと吉。なんなスクリーン・エディターって懐しいな。

昔、FM-11ってパソコンを使ってた。豪華にMC6809を2こも搭載したやつ。サブCPUは画面制御専用になってて、メインCPU側から、コマンドブロックってのにコマンドと引数を置いてコール。するとサブ側が動いて、スクロールとかを実行。

何でも、このコマンドブロック方式ってのが、大型コンピュータでも採用されてたらしくし、自慢の種になってた。

pty

こんな面白い記事を見付た。

Using pseudo-terminals (pty) to control interactive programs

大事な技術だな。普段は表に出て来る事はないけど。puttyでも使っているかな。

マスター/スレーブって、今は放送禁止用語になっちゃってるのか。


This year's Index

Home