edコマンド世界ではwqは1文字?
謎
ちょっとedを実装してたら謎を見つけました
GNU 'ed' Manual より引用.
All ed commands are single characters
全てのedのコマンドは1文字です
(1,$)wq file Writes the addressed lines to file, and then executes a 'q' command.
(1,$)wq file ファイルに指定した行を書き出し, 'q' コマンドを実行する
wq
は1文字だった…?
そんなことはないと思うんだがなあ.
指摘
(.)klcがそのまま小文字受け取るから実用上困るんだよなあ…wqだけ特別扱いすることで対処したけど
— エヌユル (@ncaq) 2016年10月25日
w コマンドと q コマンドを連続して書いてるだけなんじゃないのかな https://t.co/5Bnvd4omyt
— 齊藤敦志 (@SaitoAtsushi) 2016年10月25日
.@SaitoAtsushi 確かにソースコード読んでもそんな感じなんですけど,waとかwcは通らないのでなんか釈然としない…
— エヌユル (@ncaq) 2016年10月25日
実装を読んで見ればまあ動いてる原理はわかるんだけど,wqが特別に通るのがなんか納得いかねえ…
— エヌユル (@ncaq) 2016年10月25日
実装
gnu edでの実装は以下のようになっていた.
やはりコマンドは1文字という原則から外れ, 2文字を処理しているように見える.
q
がw
のparameters
という扱いなら,
矛盾はなかったのだが.
klc
コマンドは,
lc
はparameters
扱いになっているため,
矛盾はない.
/* execute the next command in command buffer; return error status */
static int exec_command( const char ** const ibufpp, const int prev_status,
const bool isglobal )
{
const char * fnp;
int gflags = 0;
int addr, c, n;
const int addr_cnt = extract_addr_range( ibufpp );
if( addr_cnt < 0 ) return ERR;
*ibufpp = skip_blanks( *ibufpp );
c = *(*ibufpp)++;
switch( c )
{
// 省略
case 'w':
case 'W': n = **ibufpp;
if( n == 'q' || n == 'Q' ) ++*ibufpp;
if( unexpected_command_suffix( **ibufpp ) ) return ERR;
fnp = get_filename( ibufpp );
if( !fnp ) return ERR;
if( addr_cnt == 0 && last_addr() == 0 )
first_addr = second_addr = 0;
else if( !check_addr_range( 1, last_addr(), addr_cnt ) )
return ERR;
if( !def_filename[0] && fnp[0] != '!' ) set_def_filename( fnp );
if( traditional() && !fnp[0] && !def_filename[0] )
{ set_error_msg( "No current filename" ); return ERR; }
addr = write_file( fnp[0] ? fnp : def_filename,
( c == 'W' ) ? "a" : "w", first_addr, second_addr );
if( addr < 0 ) return ERR;
if( addr == last_addr() ) set_modified( false );
else if( modified() && !scripted() && n == 'q' &&
prev_status != EMOD ) return EMOD;
if( n == 'q' || n == 'Q' ) return QUIT;
break;
default : set_error_msg( "Unknown command" ); return ERR;
}
if( gflags && !display_lines( current_addr(), current_addr(), gflags ) )
return ERR;
return 0;
}