Emacsで制御コードを入力する

Emacsを使っているときでも時々制御コードを直接入力したいことがある。

  • 文字列を置換するときに改行を入れたい
  • 強制的にタブを入力したい(たいていのモードではタブはインデントの設定になる)

ちょっとググれば、Ctrl-qを使うことで改行やタブが入力できることが分かる。改行はCtrl-q Ctrl-j、タブはCtrl-q Ctrl-iだ。しかし、なぜ改行がCtrl-jでタブがCtrl-iなのかはあまり説明がない。こういうのは理屈が分かっていないと覚えられないし、何より応用が効かない。例えばForm Feed (0x0C) を入力したい場合はどうすれば良いだろう?

"emacs ctrl-q"でググったところ、Google Booksにある"Unix Power Tools"という本の一部が引っかかった。曰く:

Ctrl-q tells Emacs that the next character you types is text, not a part of some command. So the sequence Ctrl-q Ctrl-l inserts the character Ctrl-l into your file;

適当な訳

Ctrl-qは、あなたがタイプしたのがテキストで、コマンドの一部ではないことをEmacsに伝える。そのため、Ctrl-q Ctrl-lというシーケンスは文字Ctrl-lをファイルに入力する。

うーん、これだけだとちょっと分からない。と、ここでWikipediaの「コントロールキー」の項目を見ると、コントロールキーの歴史として以下のようなことが書いてある。

テレタイプ端末、及び初期のコンピュータキーボードでは、コントロールキーを押しながら他のキーを押すと、生成されるASCIIの下位5ビット以外がゼロとなった。これによりユーザーはASCIIの非表示文字である最初の32文字 (0x00 - 0x1f) を生成、入力できる。

これで何となく分かった気がする。小文字のjはASCIIコードで0x6A、2進数なら01101010。下位5ビット以外を0にすると00001010 = 0x0A、つまり改行を表すLFになる。また、小文字のi (0x69 = 01101001) についても同様に処理すれば00001001 = 0x09 (タブ) となる。つまり、入力されたキーのASCIIコードと0x1fとのANDを取ればよい。

f:id:wagavulin:20170209212057p:plain

ということで、原理が分かればあとはASCIIコード表と簡単な計算でどんな制御コードでも入力できるようになる。と思ったのだが、実際にはCtrl-qの後に入力できる文字は限られているようだ。例えば、Ctrl-q Ctrl-, を打っても"C-, is not a valid character"と言われてしまう。試した結果、Ctrl-q Ctrlの次に以下のキーを押せば0x00-0x1Fを入力することができる。

Ctrl-q Ctrlの後に押すキー そのキーの16進表記 上位3ビットを0 (=入力される制御コード)
@ 0x40 0x00
a 0x61 0x01
b 0x62 0x02
c 0x63 0x03
d 0x64 0x04
e 0x65 0x05
f 0x66 0x06
g 0x67 0x07
h 0x68 0x08
i 0x69 0x09
j 0x6A 0x0A
k 0x6B 0x0B
l 0x6C 0x0C
m 0x6D 0x0D
n 0x6E 0x0E
o 0x6F 0x0F
p 0x70 0x10
q 0x71 0x11
r 0x72 0x12
s 0x73 0x13
t 0x74 0x14
u 0x75 0x15
v 0x76 0x16
w 0x77 0x17
x 0x78 0x18
y 0x79 0x19
z 0x7A 0x1A
[ 0x5B 0x1B
\ 0x5C 0x1C
] 0x5D 0x1D
^ 0x5E 0x1E
_ 0x5F 0x1F

GNOME Planner for Windows 独自ビルド版

リポジトリ構成を変更することにしたので一時公開停止中。

最近ちょいとプロジェクト管理ツールが使いたくなった。プロジェクト管理ツールと言えばMicrosoft Projectが有名だが、如何せん値段が高いし、そこまで高機能である必要はない。代わりのツールを色々検索してみたが、この手の作業はブラウザでやるのが流行りのようで、多くはWebアプリになっている。できればオフラインで使えて、かつ余計なもの(Javaランタイムとか)を入れなくて良いのがいい。あと、インストーラなしでフォルダコピーだけで使えるともっといい。

そうなると候補になるのはGNOME Plannerくらい。ただ、公式のWindows版を試したところファイル書き込み時にクラッシュする問題があって使えない。公式のメーリングリストにも似たようなレポートが来ているが、まだ修正されてないようだ。というより、ここ最近は各国語の翻訳に関するコミットはあるものの、ソースコードの修正はほとんど行われていないようだ。

ということで、自分で直してみたら一応動かすことに成功。

f:id:wagavulin:20170121221653p:plain

せっかくなのでGitHubに上げたので使ってみて欲しい。

ダウンロード

ダウンロードはGitHubのリリースページから。なお、ソースコードはここ

インストールと起動

インストールはZipファイルを展開するのみ。展開したフォルダ中のbin/planner.exeを起動すれば使えるはず。インターネット上からダウンロードしたexeを実行しようとすると多分メッセージが出るが、元のコードから余計な機能を加えたりはしてないので大丈夫。もちろんそれを信じるかは各人の判断だが。

制限

とりあえず動くようにしただけなのでまだ色々制限はある。

  • UIは英語のみ
  • 日本語の入力はできるが、IMEのウィンドウが別途画面左上に表示されるので見にくい
  • ファイル名・パスに日本語があると開けない
  • ユーザガイドは入ってない
  • ビルドオプションで指定できる機能はほぼすべてオフ(pythonプラグインやデータベースサポートなど)
  • インストーラはなくファイルの関連付けはしないので、.plannerファイルのダブルクリックで開くことはできない

そのうち直そうと思うが、現状でもとりあえず使う分にはそんなに困らないと思う。

バグ報告など

自分の環境(Windows 10 64bit)でしか動作チェックしていないので他の環境で動くかは分からない。もし問題があったらこの記事のコメントかGitHubのIssuesにでも挙げて欲しい。まあ手元にない環境での問題は多分直せないが。

あと、無事動いた場合は「Windows 7で動いた」などというだけでも助かるのでコメントしてもらえればと思う。

Bash on Windows (Windows Subsystem for Linux) でvalgrindを動かす

Windows上でLinux(Ubuntu)のバイナリを動かすBash on Windowsが発表され(Windows Subsystem for Linuxという呼び方もされているが、用語の使い分けがよく分からない)、bash, gcc, clangといったツールがWindows上で動くようになった。

gccやclangを動かすだけなら今までもCygwinやMSYSといった環境があったが、これらの環境にはvalgrindを動かすことができないという大きな問題がある。メモリリークのチェックなら他にもいくつかツールはあるが、やはりvalgrindが優秀だと思う。

Bash on WindowsならLinuxのシステムをかなり忠実に再現していて、Ubuntuのバイナリがそのまま動いているらしい。であればvalgrindもいけるはず、ということで試してみた。

インストールはapt-get install valgrindで簡単にできる。で動かしてみたところ、

$ valgrind --leak-check=full ./a.out
--15035:0:aspacem   -1: ANON 0038000000-00383d5fff 4022272 r-x-- SmFixed d=0x000 i=421087  o=0       (0) m=0 /usr/lib/valgrind/memcheck-amd64-linux
--15035:0:aspacem  Valgrind: FATAL: aspacem assertion failed:
--15035:0:aspacem    segment_is_sane
--15035:0:aspacem    at m_aspacemgr/aspacemgr-linux.c:1502 (add_segment)
--15035:0:aspacem  Exiting now.

というエラーを吐いて終了。a.outコマンドを実行するのに失敗しているという分けでもなく、valgrind --helpだけでも落ちる。

ググってみたところ、bash on windowsのGithubによれば、valgrind-3.11.0をソースから入れれば動くらしい。

ということでやってみた。

ソースのダウンロードは公式サイトのダウンロードページから。ビルドは特に難しいことなく、configure; make; make installでできるっぽい。aptで入れたvalgrindとぶつからないよう、--prefixオプションを使おう。

$ tar xvjf valgrind-3.11.0.tar.bz2
$ cd valgrind-3.11.0
$ ./configure --prefix=/usr/local/valgrind-3.11.0
$ make -j4
$ sudo make install

これだけでビルド・インストールできたので、早速メモリリークを起こすサンプルを作って試したところ……

$ /usr/local/valgrind-3.11.0/bin/valgrind --leak-check=full ./a.out
==15064== Memcheck, a memory error detector
==15064== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==15064== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==15064== Command: ./a.out
==15064==
==15064==
==15064== HEAP SUMMARY:
==15064==     in use at exit: 1 bytes in 1 blocks
==15064==   total heap usage: 1 allocs, 0 frees, 1 bytes allocated
==15064==
==15064== 1 bytes in 1 blocks are definitely lost in loss record 1 of 1
==15064==    at 0x4C2B145: operator new(unsigned long) (vg_replace_malloc.c:333)
==15064==    by 0x40071E: main (main.cpp:9)
==15064==
==15064== LEAK SUMMARY:
==15064==    definitely lost: 1 bytes in 1 blocks
==15064==    indirectly lost: 0 bytes in 0 blocks
==15064==      possibly lost: 0 bytes in 0 blocks
==15064==    still reachable: 0 bytes in 0 blocks
==15064==         suppressed: 0 bytes in 0 blocks
==15064==
==15064== For counts of detected and suppressed errors, rerun with: -v
==15064== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 1 from 1)

できた!

これでBash on WindowsでのC/C++の開発も結構いけるんじゃないだろうか。

ちなみに、valgrindのビルドにかかった時間(make -j4の時間)は、Windows 10 (64bit)、Core i7-2600 (3.4GHz)、RAM 16GB、SSDの環境で約47秒。また、このPCのVMwareの仮想環境に入れたUbuntu-16.04 (64ビット)の環境では、make -j4で1分12秒かかった。それぞれ1回しかやっていないので正確な計測ではないが、Bash on WindowsのC言語開発環境のパフォーマンスはVMware上のLinuxと比べてもそれほど大差はないのかもしれない。

GCC7ではエラーメッセージが改善されるらしい

プログラムを書いているときには当然色々ミスをするが、GCC(gcc/g++)が出すメッセージは Clang(clang/clang++)に比べて分かりにくい/不親切なことが多い。

例えば、FooBarという名前のクラスが宣言されていて、それを使おうとしたときに以下のように間違ってFooBazと書いたとする。

int main(int, char**){
    FooBaz foobar;
}

g++-5.4.0でコンパイルした場合のメッセージは以下のようになる。

g++ -g -Wall -Wextra   -c -o main.o main.cpp
main.cpp: In function 'int main(int, char**)':
main.cpp:9:5: error: 'FooBaz' was not declared in this scope
     FooBaz foobar;
     ^

最新のg++-6.2では、エラーの位置を示す'^'が波線(~~~~~~)になるが、内容は特に変わらない。

/usr/local/gcc-6.2.0/bin/g++ -g -Wall -Wextra   -c -o main.o main.cpp
main.cpp: In function 'int main(int, char**)':
main.cpp:9:5: error: 'FooBaz' was not declared in this scope
     FooBaz foobar;
     ^~~~~~

clang++-3.8では以下のように修正候補を挙げてくれる。

clang++ -g -Wall -Wextra   -c -o main.o main.cpp
main.cpp:9:5: error: unknown type name 'FooBaz'; did you mean 'FooBar'?
    FooBaz foobar;
    ^~~~~~
    FooBar
main.cpp:3:7: note: 'FooBar' declared here
class FooBar {
      ^
1 error generated.

あるいは、以下のように文末のセミコロンを忘れた場合、

int main(int, char**){
    FooBaz foobar
    foobar.method1();
}

g++-5.4、g++-6.2、clang++-3.8でコンパイルした結果はそれぞれ以下のようになる。

# g++-5.4
g++ -g -Wall -Wextra   -c -o main.o main.cpp
main.cpp: In function 'int main(int, char**)':
main.cpp:10:5: error: expected initializer before 'foobar'
     foobar.method1();
     ^

# g++-6.2
/usr/local/gcc-6.2.0/bin/g++ -g -Wall -Wextra   -c -o main.o main.cpp
main.cpp: In function 'int main(int, char**)':
main.cpp:10:5: error: expected initializer before 'foobar'
     foobar.method1();
     ^~~~~~

# clang++-3.8
clang++ -g -Wall -Wextra   -c -o main.o main.cpp
main.cpp:9:18: error: expected ';' at end of declaration
    FooBar foobar
                 ^
                 ;
1 error generated.

g++では、セミコロンを忘れた行の次の行がエラーとなっているが(普通に解析したらそうなるだろう)、clang++ではちゃんと「セミコロンがない」というメッセージになっている。

これがClangを使う一つの理由だったのだが、Phoronixの記事によれば、GCC7ではエラーメッセージか改善され、タイプミスに対する修正のヒント(Fix-it hints)を出すようになるらしい。

また、その場所にアンダーラインが引かれる、セミコロンがないことに関するFix-it hintsを出す、などと書かれているで、多分Clangと似たような感じになるのだろう。

一昔前まで、フリーで使えるC/C++コンパイラと言えばGCC一択だったところにClangの登場し、GCCにない機能が色々使えるようになったが、それに刺激されたGCCも改善が進んでいるようだ。