標準入力が pipeかどうかの判定
the silver searcherは stdinが ttyに関連付けられていないと
標準入力が pipeと判定しているんですが、そのせいで単純に
エディタから agコマンドを叩くと標準入力待ちになってしまいます。
問題となる部分は src/options.cの以下の部分です
/* stdin isn't a tty. something's probably being piped to ag */ if (!isatty(fileno(stdin))) { opts.search_stream = 1; }
一応確かめてみます。
#include <stdio.h> #include <unistd.h> int main (void) { if (isatty(STDIN_FILENO)) { printf("stdin is tty\n"); } else { printf("stdin is not tty\n"); } return 0; }
ターミナルエミュレータで実行すると以下のような結果が得られます。
% ./isatty.out stdin is tty % echo hoge | ./isatty.out stdin is not tty
しかし Emacsからコマンドを叩いて見ると以下のような結果になります。
(call-process-shell-command "./isatty.out" nil t) ;; => stdin is not tty (call-process-shell-command "echo hoge | ./isatty.out" nil t) ;; => stdin is not tty
ttyに関連づいていないので, 両方 elseの方に入ってしまい、結果が異なります
まあ当たり前の挙動ではあるんですが、the silver searcherが期待するものとは異なります。
もっとまともな判定方法がないのかと思って調べてみました。
解決方法
S_ISFIFOで標準入力を調べれば、ttyに関連づいているか関係なく
pipeかどうかを判定できるようです。(Perlだと -p FILEで OK)
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> int main (void) { struct stat st; int ret; ret = fstat(STDIN_FILENO, &st); if (ret != 0) { perror("stat:"); return 1; } if (S_ISFIFO(st.st_mode)) { printf("stdin is fifo\n"); } else { printf("stdin is not fifo\n"); } return 0; }
ターミナルエミュレータでの実行結果は
% ./stat.out stdin is not fifo % echo hoge | ./stat.out stdin is fifo
Emacsからの実行は以下のようになります。
(call-process-shell-command "./stat.out" nil t) ;; => stdin is not fifo (call-process-shell-command "echo hoge | ./stat.out" nil t) ;; => stdin is fifo
同じになりました。
おわりに
pull requestできそうならします。