line-edit.scm
壊れた
台所の3口コンロのうちの火力が強いメインのやつが壊れた。料理担当の女房がおお弱り。新品への買い替えが必要との事。品が無くて1月待ちとガス屋さんから連絡が来た。
そう言えば、友人の所の風呂炊き給湯器が壊れ、半年待ちとか言っていた。ホームセンターからたらいを買ってきて、カラスの行水をやってると言ってたけど、いまだ不自由してるのだろうか?久しぶりに連絡取ってみようかな。
TVに繋いでいるHDDが壊れかけている。起動したりしなかったり。叩くと直る事がある。重症っぽい診断。もう10年ぐらいは使っているんで、諦めて買い替えるか。値上がりしてるんだろうな。怖くて調べられないですよ。
笑わない数学なんてのを撮りそこねた。見るニュートン誌だから諦めてもいいんだけど、ものは試しとNHKプラスに挑戦。firefoxはサポートしてませんですって。ググル系のブラウザーにしなさいって、多様性を損なう事になるけど、それで委員会? たかがブラウザーごときで、系列を指定させるって、何考えているんだ。皆様のNHKじゃなくて、ググルに媚びを売るNHK。
ついでに、働き方改革を謳うのは、新たな番組制作をしたくない言い訳。おかげで、平家物語なんて言う昔の人形劇(勿論、再放送)を見てるぞ。ひょっこりひょうたん島の人形劇を彷彿させてくれて、これはこれで、楽しいけど。
SSDの延命
転ばぬ先の何とやらとは、よく聴く話だ。たまたま、こんなのに出会った。
今迄Windowsは、コールド起動とシャットダウンって運用してた。これだと不要な読み書きが発生するんで、SSDにはよくないとの事。スリープを使えとな。
スリープからの復帰で、ネットに繋らないとかマウスの認識に失敗するとか、画面がブラックアウトしないかとか、OSSなOSで報告される事象がないか、点検しながら使ってみよう。
もし駄目なら、元の運用に戻すだけですから。それから、仮想記憶がどーたらって示唆もあるけど、オイラーは、そんなメモリー喰いな使いかたはしてない。メモリー喰いの最大なやつは、ブラウザーですって知ってるからね。
そもそもWindowsを上げさげして使う習慣がついたのは、昔勤めていた会社の情報システム部門の影響だな。毎朝rebootしないとWindowsNTが可笑しくなると言う話からだ。その頃オイラーは、FreeBSD 2.2.8だからでWebをやってたけど、Uutimeが軽く1000日を越えてもなんなく動いていた。それに引き換えWindowsって駄目なOSなのねってのが、刷り込まれてしまったのさ。
今はまともになったっぽい。嬉しいのは、VMWAREで仮想OSを起動したままに出来る事。起動時に、指定したメモリーサイズ分のワークファイルが作成されるのは知ってたけど、いかんともしがたいって事で、放置してたんだ。今度はそんな事を気にしなくてもよくなるのか。
at OpenBSD
OpenBSDなコンソール /dev/ttyC0 でgoshを動かしてみる。
Scm_Getc
が、'\r' を受領した後、 Scm_Putc
が呼び出された。
(gdb) bt #0 Scm_Putc (c=10, p=0x431c2ee0) at ./portapi.c:160 #1 0x09448c29 in libionewline (SCM_FP=0x43174180, SCM_ARGCNT=1, data_=0x0) at libio.scm:787 #2 0x09327c40 in run_loop () at ././vmcall.c:192 #3 0x0931ff9f in user_eval_inner (program=<optimized out>, codevec=<optimized out>) at vm.c:1572 #4 0x0932102a in apply_rec (vm=0x6a007acc, proc=<optimized out>, nargs=<optimized out>) at vm.c:1691 #5 Scm_ApplyRec (proc=<optimized out>, args=<optimized out>) at vm.c:1711 #6 safe_eval_wrap (kind=<optimized out>, arg0=<optimized out>, args=0xb, cstr=0x15f41070 "(read-eval-print-loop)", env=0x293\ 20508 <userModule>, result=0x0) at vm.c:1844 #7 0x0932110e in Scm_EvalCString (expr=0x15f41070 "(read-eval-print-loop)", env=0x29320508 <userModule>, packet=0x0) at vm.c\ :1877 #8 0x15f44d21 in enter_repl () at main.c:753 #9 0x15f4546e in main (ac=1, av=0xcf7f8974) at main.c:897
このPutsは、REPLのPの部分か。ならば、GetsはRの部分なんだな。と、言う事はGetcでエコーが行われているんだな。
vbox$ wsconsctl display.type=vga-pci display.fontwidth=8 display.fontheight=16 display.emulations=vt100 display.screentypes=80x25,80x25bf,80x40,80x40bf,80x50,80x50bf :
gosh$ 123A ;; C-M-x Unknow keystroke C-[. Type M-h b for the list of key bindings. gosh$ 123 ;; ESC C-x
easy way by Debian
こんなアドバイスが有った。
shiro ESC [ dd;dd R は現在のカーソル位置問い合わせの返事です。ターミナルは「現在の表示内容」は覚えてないので、 「範囲指定して取り込み」ということはやってません。キーストロークを拾ってGauche側で内容を管理しています。libsrc/text/line-edit.scm あたり。
少し、下調べしてみる。
sakae@pen:/tmp$ strace -o LOG gosh gosh$ 89 89 gosh$ (exit) sakae@pen:/tmp$ wc LOG 1580 10595 137582 LOG
straceを使ってgoshをHack(89)してみた。終了はSIGQUITでもいいんだけど、画面制御がおかしくなるので、正しい作法の(exit)です。多少ログサイズが増えるけど、よしとしよう。
で、膨大なログの最後の方300行ぐらいを見ればいいかな。
ioctl(0, TCGETS, {B38400 -opost isig -icanon -echo ...}) = 0 : read(0, "8", 1) = 1 : read(0, "9", 1) = 1 select(1, [0], NULL, NULL, {tv_sec=0, tv_usec=0}) = 0 (Timeout) write(1, "\33[?25l", 6) = 6 write(1, "\33[0m", 4) = 4 write(1, "\33[31;1H", 7) = 7 write(1, "gosh$ ", 6) = 6 write(1, "\33[J", 3) = 3 write(1, "\33[31;7H", 7) = 7 write(1, "8", 1) = 1 write(1, "\33[31;8H", 7) = 7 write(1, "9", 1) = 1 write(1, "\33[31;9H", 7) = 7 write(1, "\33[?25h", 6) = 6 read(0, "\r", 1) = 1 : ioctl(0, TCGETS, {B38400 -opost isig -icanon -echo ...}) = 0 ioctl(0, SNDCTL_TMR_START or TCSETS, {B38400 opost isig icanon echo ...}) = 0 ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0 write(1, "\33[0m", 4) = 4 write(1, "\33[?25h", 6) = 6 exit_group(0) = ? +++ exited with 0 +++
ご丁寧に、読み取ったデータを書出しているね。エスケープシーケンスは前回の資料で要確認だな。その他、画面制御の為のioctlが頻繁に発せられている事が分る。
また、ログの前段階で、termios.soを読み込んでいるので、画面制御をそれに委ねているのかな? gauche.termiosを見る限りでは、今回の用例には、機能不足のように思える。
truss by FreeBSD
BSDでシステムコールの追跡をしようと思ったら、ktrace/kdumpが頭に浮かぶ。ただ残念な事に、詳細が出てこないんだ。何かヒントは無いものかとktrace(1)してたら、dtrace,trussなんてのが紹介されてた。
HISTORY The truss command was written by Sean Eric Fagan for FreeBSD. It was modeled after similar commands available for System V Release 4 and SunOS.
昔使った事があるな。早速、コンソールでhackしてみる。
ioctl(0,TIOCGETA,0xffbfeb38) = 0 (0x0) ioctl(0,TIOCGETA,0xffbfe3c8) = 0 (0x0) ioctl(0,TIOCGETA,0xffbfe3d8) = 0 (0x0) ioctl(0,TIOCSETA,0x2186bc34) = 0 (0x0) : write(1,"gosh$ ",6) = 6 (0x6) write(1,"\^[[6n",4) = 4 (0x4) read(0,"8",1) = 1 (0x1) read(0,"9",1) = 1 (0x1) read(0,"\r",1) = 1 (0x1) SIGNAL 3 (SIGQUIT) code=SI_KERNEL
goshを起動して89を入力、そして^\でSIGQUITを発生。入力に対するechoの処理が無いぞ。 次は、PuTTYから実行。
ioctl(0,TIOCGETA,0xffbfea58) = 0 (0x0) ioctl(0,TIOCGETA,0xffbfe2e8) = 0 (0x0) ioctl(0,TIOCGETA,0xffbfe2f8) = 0 (0x0) ioctl(0,TIOCSETA,0x21867b44) = 0 (0x0) : read(0,"9",1) = 1 (0x1) select(1,{ 0 },0x0,0x0,{ 0.000000 }) = 0 (0x0) write(1,"\^[[?25l",6) = 6 (0x6) write(1,"\^[[0m",4) = 4 (0x4) write(1,"\^[[31;1H",7) = 7 (0x7) write(1,"gosh$ ",6) = 6 (0x6) write(1,"\^[[J",3) = 3 (0x3) write(1,"\^[[31;7H",7) = 7 (0x7) write(1,"8",1) = 1 (0x1) write(1,"\^[[31;8H",7) = 7 (0x7) write(1,"9",1) = 1 (0x1) write(1,"\^[[31;9H",7) = 7 (0x7) write(1,"\^[[?25h",6) = 6 (0x6) read(0,"\r",1) = 1 (0x1) : write(1,"\r\n",2) = 2 (0x2) : SIGNAL 3 (SIGQUIT) code=SI_KERNEL
89の入力に対してちゃんと画面の再描画をやってる。この違いをgauche上のコードで検討すればいいんだな。
なお、画餅になるけど、ports/devel/straceなんていうtrussより親切なやつがあるんだけど、procfsの問題で、パッケージが作成されていない。古いFreeBSDならOKみたいだ。 問題発覚が、7/20ってなってるから、そのうち直るかな。
mount -t procfs proc /proc
ちょっと悔しいので、マウントしてから、goshのproc statusを確認。
sakae@fbox:/proc/6631 $ cat status gosh 6631 6628 6631 6627 ttyv0 ctty 1661067538,772988 0,137273 0,24224 ttyin 1001 1001 1001,1001,0,5 -
意味は、procfs(5)に説明されてた。興味ある所では、
• device name of the controlling terminal, or a minus sign (“-”) if there is no controlling terminal. • a list of process flags: ctty if there is a controlling terminal, sldr if the process is a session leader, noflags if neither of the other two flags are set. • the wait channel message (;; ttyin is this case)
こんな所かな、とんだ道草だわい。
gosh 6707 818 6707 818 pts/2 ctty 1661068675,264285 0,147724 0,23324 ttyin 1001 1001 1001,1001,0,5 -
ついでに、PuTTYからの起動status
into line-edit
ここからは、libsrc/text/line-edit.scmのあたりを見ていく。それに先だって、支援してくれている、console.scmの支援体制を確認。
(export <vt100> <windows-console> call-with-console putch putstr getch get-raw-chars chready? canonical-mode? beep query-screen-size query-cursor-position move-cursor-to hide-cursor show-cursor cursor-down/scroll-up cursor-up/scroll-down reset-terminal clear-screen clear-to-eol clear-to-eos set-character-attribute reset-character-attribute with-character-attribute ensure-bottom-room make-default-console vt100-compatible?))
こういう時、pythonみたいに、関数がどのモジュール由来か表記してあると楽だ。けど、鬱陶しい側面もあるので、コードを書くのを優先するか、読むのを優先するかで違ってくるな。
まずは、入力されないと始まらないって事で、getchに着目して使われいる所を探してみた。
(define (next-keystroke ctx) (if (queue-empty? (~ ctx'keystroke-queue)) (let1 ch (getch (~ ctx'console)) (if (and (%sigcont-received?) (canonical-mode? (~ ctx'console))) (let loop () (let1 ch (getch (~ ctx'console) 10000) ;10ms wait (unless ch (raise 'sigcont-received)) (loop))) ch)) (queue-pop! (~ ctx'keystroke-queue))))
ここから、next-keystrokeを探して上位に辿っていく。
(define (handle-command h ch loop redisp) : [(is-a? h <keymap>) (let* ([ch (next-keystroke ctx)] [h (keymap-ref h ch)]) (handle-command h ch loop redisp))]
このあたりかなあ? どうも自信がない。バックトラックします。
折角取得したtrussの結果を活用。selectの後に、エスケープシーケンスが続いている。
write(1,"\^[[?25l",6) = 6 (0x6) ;; hide-cursol write(1,"\^[[0m",4) = 4 (0x4) ;; reset-character-attribute ?? : write(1,"\^[[?25h",6) = 6 (0x6) ;; show-cursol read(0,"\r",1) = 1 (0x1)
write出力から、console.scmを参照して、エスケープパターンを割り出してみた。それをline-editに適用すると、%redisplay の中の一節に辿りつく。
consoleでの実行では、どうも%redisplayがすっかり抜け落ちているように見える。
ESC疑惑 ?
ちゃんとエスケープシーケンスが実行出来無いのでは? M-h h こんなキーシーケンスで、説明が得られる
Gauche input editing quick cheat sheet: M-h b for keymap M-h k <keystroke> ... for help of specific keystroke :
その時のtrussの結果。
write(1,"\^[8",2) = 2 (0x2) read(0,"\^[",1) = 1 (0x1) : select(1,{ 0 },0x0,0x0,{ 0.001000 }) = 1 (0x1) read(0,"h",1) = 1 (0x1) read(0,"h",1) = 1 (0x1) : write(5,"Gauche input editing quick cheat"...,665) = 665 (0x299) :
最初にESCが送られてから、h h て流れになるのね。Mは、慣れでALTキーを利用。このキーの代わりに、C-[ とか、純粋にESCキーを押すと、
sakae@fbox:/tmp $ gosh Unknown keystroke C-[. Type M-h b for the list of key bindings. gosh$ hh
こんな注意をうけた。微妙な所だな。
コンソールで同じ事をやると、全くなしのつぶて、注意も受けないし、反応も全くない。
ただ、ESCとかALTキーを多用するvi,emacsは、コンソール上で何等問題なく動いているんで?????な訳ですよ。迷宮入りさせて、後は専従班が細々と捜査を継続するか。時効は無いからね。
sakae@fbox:/tmp $ truss -o LOG truss /bin/echo hello
こういう息抜きをするのは、scheme脳になった人?
vt(4)
SYNOPSIS options VT_ALT_TO_ESC_HACK=1
これは何?
/sys/dev/vt/vt_core.c
#if VT_ALT_TO_ESC_HACK if (vd->vd_kbstate & ALKED) { /* * Prepend ESC sequence if one of ALT keys down. */ terminal_input_char(vw->vw_terminal, 0x1b); }
もろにALTキーをESCキーに置き換えている。あれ? ALTキーって、SHIFTキーみたいにモデファイアーな位置付と思っていたけど、実体があるそれ自身でキーコードを発生するやつなのか。
不安の種が増えたので、裏取り。Altキー やっぱり、修飾キーだった。思い込みはいかんぞな。
実体の無いキーなら、ESCキーの代わりにはならないはず。コンソールでviを使って確認したら、やっぱり機能してなかった。どんなハードとの組み合わせで働くのだろう? 謎がまた一つ増えたぞ。
ちなみに、今のカーネルでは、この機能は有効になっていないっぽい。但し、/sys/conf/NOTESにはカーネル・コンフィグの全てのオプションが列挙されてて、そこにもちゃんと説明されてたぞ。こういう場合は、兄弟OSであるOpenBSDも調べてみればいいのか。
ああ、キーボードで思い出した。カウボーイは西部で馬が倒れても、鞍だけは持って行くとな。キーボードは、人間とコンピュータを結びつける超重要なインターフェース。理想のキーボードを作っちゃった高名な先生がいましたねぇ。お元気かしら? SICPの読書会では、よく同席させて頂きましたけど、あれから何年達つだろう。
i
笑わない数学の復習、虚数編。数の扱いについて厳密な要求をしてくるschemeに登場願う。で、舞台は、 ガウス平面。花形な場面です。
まずは、超有名なあれ。 e(πi) = -1 same as e(πi) + 1 = 0
gosh$ (use math.const) gosh$ (exp (* pi 0+1i)) -1.0+1.2246467991473532e-16i
上記で右辺が0となってる式の方がかっこいいと思うぞ。1はかけ算の単位元だし、0は足し算の単位元だ。さりげなく取入れられてるのが審美眼的。
gosh$ (define I 0+1i) I gosh$ (exp (* pi/2 I)) 6.123233995736766e-17+1.0i gosh$ (exp (* 0 I)) 1.0
超有名なやつはπ回転させたやつ。π/2 と 回転無しもやってみた。なお、分かり易いように虚数単位を I としてみた。微妙な誤差に惑わされるかも知れないけど、取り敢えず許せ。ちゃんとそれっぽく表示させたいなら、real-partとかで取出してきて、丸めてしまえばよい。
gosh$ (define z (exp (* 1 I))) z gosh$ z 0.5403023058681398+0.8414709848078965i gosh$ (angle z) 1.0 gosh$ (magnitude z) 1.0 gosh$ (radians->degrees 1) 57.29577951308232
これらの式に出て来る偏角はラジアン単位だ。普通の度に変換する手続も用意されてる。コンビニな世界だなあ。
gosh$ (cos 1) 0.5403023058681398 gosh$ (sin 1) 0.8414709848078965
単位長(magnitude)のベクトルの偏角(angle)1での座標位置が、ei になるんだね。