mg

疑問解決

散歩のおり、信号が赤だったのでSTOP。ひょいと目の前の電柱を見上げたら、風速計が2個、元気よく回っていた。何これ。停電した時、直発電でもしてるの、、と無い頭を捻る。

家に帰って調べてみた。

電柱の上でクルクル廻ってる小さな風車は、なんのため?!

へぇー、並々んらぬ苦労をされてるんだね。昔、蛇が鉄塔を登らないように、蛇返しってのがあるってのを聞いた事があるぞ。猿バージョンもサル所には必要そうだな。

去年の記事

毎日10個以上の悪意あるパッケージが「npm」「rubygems」経由で公開されている

おい、持て囃されているPythonは大丈夫か? 水呑場攻撃には、うってつけだぞ。

Ruby 3.2.0」公開、WASIベースのWebAssemblyへのコンパイルをサポート

そして、そうきたか。世の中JIT流行だからなあ。

emacs

前回やった、emacsのサーバー/クライアントを .bashrcに定義してみた。

alias es='emacs --daemon'
alias ek='emacsclient -e "(kill-emacs)"'
alias mg='emacsclient -t'

クライアントの起動をmgにしたのは、深遠な理由が有る(後で出て来る)。サーバーを落とすには、pkill emacsでもいいんだろうけど、ついでなのでコピペしたよ。

それから、emacsclient(1)に

-a, --alternate-editor=COMMAND
       If the Emacs server is not running, run the specified shell com‐
       mand instead.  This can also be specified via the ALTERNATE_EDI‐
       TOR environment variable.  If the value of  ALTERNATE_EDITOR  is
       the  empty string, run "emacs --daemon" to start Emacs in daemon
       mode, and try to connect to it.

こんなオプションが有り、これを組合せるといいはずなんだけど、文句を言われたので、esとして分離してる。

[sakae@arch ~]$ es

Warning: due to a long standing Gtk+ bug
https://gitlab.gnome.org/GNOME/gtk/issues/221
Emacs might crash when run in daemon mode and the X11 connection is unexpectedly lost.
Using an Emacs configured with --with-x-toolkit=lucid does not have this problem.
Starting Emacs daemon.

こんな脅かしが出て来た。専用に作れとな。面倒嫌いなので、pacman -R emacs; pacman -S emacs-nox して、置き換え。これで文句は出ないだろう。

[sakae@arch ~]$ es
Starting Emacs daemon.

それにしても、こういうエラーが出るのは、オイラーの所だけ?

[sakae@fb ~]$ mg .bashrc
emacsclient: can't find socket; have you started the server?
emacsclient: To start the server in Emacs, type "M-x server-start".
emacsclient: No socket or alternate editor.  Please use:

        --socket-name
        --server-file      (or environment variable EMACS_SERVER_FILE)
        --alternate-editor (or environment variable ALTERNATE_EDITOR)

サーバーが動いていない時に使おうとすると、警告が出てくる。

mg

FreeBSDのports/editorに有った説明。

[sakae@fb /usr/ports/editors/mg]$ cat pkg-descr
Mg is a small, fast, portable, and free (public domain) Emacs-like
editor maintained by the OpenBSD Project.  It is intended for people
who can't, or don't want to, run the real GNU Emacs, or are not
familiar with the vi(1) editor.

そして、供給元。 https://github.com/ibara/mg

OpenBSDのrisc版を動かしている時、まさか重いemacsは動かせないよなと探していて見付たもの。デフォで入っているので、こういう場合はうってつけです。

そんな訳で、何時でもemacsって叩いてしまう指を矯正する為、mgに統一する。それじゃ、OpenBSDの場合はaliasと競合しちゃうじゃん。大丈夫、aliasの方が先に検索されるんで、emacsclientが起動するのさ。本物のmgを使いたかったら \mg とするか、絶対PATHで指定すればOK。

Debianに入れてみた

sakae@deb:/tmp/mg$ ./configure
checking for C compiler... cc
checking if the compiler accepts -g -O2... yes
checking for -w compiler flag... yes
checking for OS... Linux
 :
checking for strlcat... no
checking for strlcpy... no
 :

strlcatやstrlcpyってOpenBSDの安全対策版だよなーとか思い出したぞ。普通に10秒そこらで、コンパイル完了。だって、mgってのは、Mg was formerly named MicroGnuEmacs, the name change was done at the request of Richard Stallman. 大親分からの横槍があったらしい。

派生品?

Debianでサーチしてみたら、こんな派生品っぽいのが引掛ってきた。

ng-cjk/stable 1.5~beta1-9 i386
  Nihongo MicroGnuEmacs with CJK support

ng-cjk-canna/stable 1.5~beta1-9 i386
  Nihongo MicroGnuEmacs with CJK and Canna support

ng-common/stable 1.5~beta1-9 all
  Common files used by ng-* packages

ng-latin/stable 1.5~beta1-9 i386
  Nihongo MicroGnuEmacs with Latin support

かんななんて懐しいな。今ならmozc一色だろうけど。。 時代は変わるね。

ngに対するパッチ (2016/03/01) そして懐しい人のリンクを発見。

mg自身には、こんな歴史が有るみたい。

Early release history:

+ Nov 16, 1986: First release to mod.sources
+ Mar 3, 1987: First Release (mg1a) via comp.sources.unix
+ May 26, 1988: Second release: (mg2a) via comp.sources.misc
+ Jan 26, 1992: Linux port released by Charles Hedrick. This version
  later makes its way onto tsx-11, Infomagic, and various other Linux
  repositories.
+ Feb 25, 2000: First import into the OpenBSD tree, where it is
  currently maintained with contributions from many others.

from man

オンライン・ヘルプが有るとな。キーバインドは、C-h C-h

help-help
       Prompts for one of (a)propos, (b)indings, des(c)ribe key briefly.

それから実習用にチュートリアルファイルが用意されてた。emacsに範を取ってるんだな。

TAGS
     mg supports tag files created by ctags(1), allowing the user to quickly
     locate various object definitions.  Note though that emacs uses etags,
     not ctags.

CSCOPE
     mg supports navigating source code using cscope.  However, mg requires
     cscope and cscope-indexer executables to be present in PATH for it to

MG DIRED COMMANDS
     The following are a list of the commands specific to dired mode:

言語は日本語はおろか、C言語しかサポートしないと言う潔い仕様。スクリプトを作ってカスタマイズなんて勿論ない。キーボード・マクロはかろうじて有るっぽい。

ああ、カスタマイズったら、キーバインドをかろうじて変更出来るか。下記は .mg に記述する例になる。

global-set-key ")" self-insert-command
global-set-key "\^x\^f" find-file
global-set-key "\e[Z" backward-char
set-default-mode fill
set-fill-column 72
auto-execute *.c c-mode

オイラー的に一番驚いたのがTAGSのデータベースをctagsで作れって所。etagsじゃemacsを入れないと使えないからね。その点ctagsはviでも使われていて標準ぽい。

M-.           find-tag
M-*           pop-tag-mark

そのTAGSを使うキーバインドが、オイラーと微妙に違うな。emacsでは、M-, で戻るようにしてるんで、mgも同様にしておく。unsetして、オリジナルを無効にしておこう。そうでないと二重定義になって、少々気持悪い。

vbox$ cat .mg
global-unset-key "\e*"
global-set-key "\e," pop-tag-mark

TAGS or tags

emacsはTAGSで、viやmgはtags派閥に属している。何でこんな事になるの?

取り敢えずデータの持ち方を調査。後で出て来る関数poptagを対象にした。

vbox$ grep poptag TAGS
^L
tags.c,424                             ;; 説明の為挿入(詳細は後述)
poptag(^?268,5823
vbox$ grep poptag tags
poptag  tags.c  /^poptag(int f, int n)$/

tags.cファイルの268行目に有るよって方式が、emacs流。それに対して、関数名、ファイル名、正規表現で持ってるのがvi流。

vi流の方が素直な表現と思うけどな。viとemacsの戦争が有ったんで、資源の方式はわざと統一しなかった。一度emacsと決めたら、ぬけがけは許さないよと言う事だ。後になってみれば、迷惑な話だな。

迷惑と言えば、日本国中を二分する問題がずっと続いている。そう、50Hz/60Hz問題ね。

一般に静岡県の富士川を境に、東日本は50Hz、西日本は60Hzとなっています。 これは、
電気事業が始まった明治時代、関東ではドイツから50Hzの発電機を、関西ではアメリカ
から60Hzの発電機を輸入していたことが原因といわれています。

同じような問題が他にも有るぞ。今や誰もが持ってるスマホ。この充電端子が、アプルとドロドロイドで別仕様になってる。

EUはこれに噛み付いた。アプルにくしってか、何彼と米国に対抗意識があるんで、資源の共通化からみて、共通にすべしって御旗を掲げて頑張ってる。まあ、頑張ってください。

gdb するぞ

例によって、mgをgdbする。前準備として、どこにBPを置くか下調べ。取り敢えずのTAG関係。

vbox$ grep find-tag *.[ch]
funmap.c:       {findtag, "find-tag", 1},
tags.c:         ewprintf("No previous location for find-tag invocation");
vbox$ grep pop-tag-mark *.[ch]
funmap.c:       {poptag, "pop-tag-mark", 0},

mg語とC語との対応を表しているんだな。構造体の最後の1とか0は、アリティー(引数の数)の宣言だろう。

システム備付のMakefileではコンパイル結果mgとなるんだけど、それをそのまま使おうとしてもアイリアスが勝ってしまうんで、a.aoutに変更しとく。姑息な手段だけど、一度変更しとけば、gdb \mg とかしなくて済む。

repl

何はなくともreplってか、全体の流れを追ってみる。

(gdb) b findtag
Breakpoint 1 at 0x18b9852f: file tags.c, line 151.
(gdb) b poptag
Breakpoint 2 at 0x18b98e3d: file tags.c, line 273.

(gdb) bt
#0  findtag (f=0, n=1) at tags.c:151
#1  0x18b78b5b in mgwrap (funct=0x18b98500 <findtag>, f=0, n=1) at kbd.c:461
#2  0x18b78a61 in doin () at kbd.c:167
#3  0x18b7c380 in main (argc=1, argv=0xcf7e0928) at main.c:244

ふーん、doin()ってのが核みたいだ。

keymap

つらつらdoin()を見ていくと、しきりにkeymapってのが出てくる。 keymap.cをつらつらと見ていて気になった関数 maps_add にBPを置いてみる。

(gdb) bt
#0  maps_add (map=0x394b869c <diredmap>, name=0x194bc4c0 "dired")
    at keymap.c:549
#1  0x194ee9a2 in dired_init () at dired.c:227
#2  0x194dae46 in main (argc=0, argv=0xcf7d3198) at main.c:138

この関数を終了すると、mapsの連なりにリンクされる。すこし cadr してみる。

(gdb) p *maps
$1 = {
  p_map = 0x394b869c <diredmap>,
  p_name = 0x194bc4c0 "dired",
  p_next = 0x394b843c <map_table+72>
}
(gdb) p *$.p_next
$2 = {
  p_map = 0x394b8074 <helpmap>,
  p_name = 0x194bbdfd "help",
  p_next = 0x394b8430 <map_table+60>
}
(gdb)
$3 = {
  p_map = 0x394b813c <cX4map>,
  p_name = 0x194ba3f5 "c-x 4 prefix",
  p_next = 0x394b8424 <map_table+48>
}
:
(gdb) p *$.p_next
$9 = {
  p_map = 0x394b8380 <fundmap>,
  p_name = 0x194b9516 "fundamental",
  p_next = 0x0
}

他に登録されるmapは無いかと、contしてみたら、下記の2つが登録されて、mgが動き出した。

(gdb) c
Continuing.

Breakpoint 1, maps_add (map=0x394b8808 <compilemap>, name=0x194ba1ec "compile")
    at keymap.c:549

(gdb) c
Continuing.

Breakpoint 1, maps_add (map=0x394b85e8 <cmodemap>, name=0x194bb6c4 "c")
    at keymap.c:549

c-modeとcompileモードが追加されててた。OpenBSDの人達の追加Hackだろう。kernelを開発する事を念頭においているんだな。

etags

TAGSをgrepした時の説明に、tags.c,424ってのが出てきた。424て何を表している?

ctagsのファイルフォーマットは容易に見付かるのに、etagsのそれは見付からなかった。ならばソース嫁。emacsの付属品、etags.c が単独で存在する。ならば、得意のgdb戦法だなと思ったら、各種ヘーッダーが必要。configureなんて面倒って事で、ソースとにらめっこ。

* If you want to add support for a new language, start by looking at the LUA
* language, which is the simplest.  Alternatively, consider distributing etags
* together with a configuration file containing regexp definitions for etags.

configが命綱になってるっぽい。

* Authors:
* 1983 Ctags originally by Ken Arnold.
* 1984 Fortran added by Jim Kleckner.
* 1984 Ed Pelegri-Llopart added C typedefs.
* 1985 Emacs TAGS format by Richard Stallman.
   :

Richard Stallmanも車輪の再発明をして、emacsへのロックインを狙ったんだねぇ。

やたらに行数を水増しするGNUスタイルのソースコードって趣味じゃないんだけど、それっぽいのを見付たのであげておく。8000行を越るソースから目grepで絞りこみ。ヒントはCTGSか否かね。否かは即ちETAGSて事。

put_entry (node *np)
{
  register char *sp;
  static fdesc *fdp = NULL;

  /* Output this entry */
  if (np->valid)
    {
      if (!CTAGS)
        {
          /* Etags mode */
          if (fdp != np->fdp)
            {
              fdp = np->fdp;
              fprintf (tagf, "\f\n%s,%"PRIdPTR"\n",
                       fdp->taggedfname, total_size_of_entries (np));
              fdp->written = true;
            }
          fputs (np->regex, tagf);
          fputc ('\177', tagf);
          if (np->name != NULL)
            {
              fputs (np->name, tagf);
              fputc ('\001', tagf);
            }
          fprintf (tagf, "%"PRIdMAX",", np->lno);
          if (np->cno != invalidcharno)
            fprintf (tagf, "%"PRIdMAX, np->cno);
          fputs ("\n", tagf);
        }

肝が見付かった。

/*
 * Return total number of characters that put_entries will output for
 * the nodes in the linked list at the right of the specified node.
 * This count is irrelevant with etags.el since emacs 19.34 at least,
 * but is still supplied for backward compatibility.
 */
static ptrdiff_t
total_size_of_entries (node *np)
 :

苦労した割には、実入りがないな。昔のRMSはきっと、こう考えたんじゃなかろうか?

ファイル毎に表示用のbufferが用意される。ならばTAGSデータもファイル毎に有るのが自然だろう。とはいいつつ、DB風にしてTAGSデータを一つのファイルにしたい。

ファイル毎のブロックにしよう。ブロックの区切はフォームフィードでいいだろう。ブロックの最初にはヘッダーとして、収納してるファイル名と、後ろに続くエレメントの文字数がいいな。こうしておけば、ファイル破損の検出も出来る。

まあ、どうでもいい事だけど、想像するのは楽しいな。


This year's Index

Home