2007年12月11日火曜日

D言語で相対パスを絶対パスに変換するの巻(コマンドプロンプトでコンテキストメニューを開く)

 コマンドプロンプトで普段の作業をするときに困ってしまうのが、ファイルのプロパティとか見るとき。普通にマウスを使えば右クリックで簡単に見ることができるのですが、CUIからだと、もうどうしようもない。

 そんな中、見つけたのがここにあった「単機能ツール集」の「コンテキストメニュー」です。これさえあれば、コマンドプロンプトでコンテキストメニューが開ける!・・・と思ったのも束の間。なんと、このツールは絶対パスしか引数で受け取ってくれなかったのです。もともと、そんな使い方は想定されていなかったのかな?

 という訳で、必要なら自分で作ってしまおう、と相対パス->絶対パスの変換ツールを作ってみました。

toabs.d

import std.stdio;
import std.string;
import std.file;
import std.path;
import std.process;

void main(string[] args){

if(args.length < 2)
return;

if(args.length < 3){
// path only
string path = get_abs_path(args[1]);
if(find(path," ") != -1)
path = "\"" ~ path ~ "\"";
printf(std.file.toMBSz(path));

} else {
// include command
string path[];
path.length = args.length - 2;
foreach(i, p; args[2 .. $]){
path[i] = get_abs_path(p);
if(find(path[i], " ") != -1)
path[i] = "\"" ~ path[i] ~ "\"";
}

string com = args[1] ~ " ";
foreach(p; path){
com ~= p;
com ~= " ";
}
execute(com);
}
}

string get_abs_path(string path){

if(isabs(path))
return path;

string atm[] = split(path, "\\");
int loc;

path = getcwd();

foreach(s; atm){
switch(s){
case ".":
// current directory
break;
case "..":
// parent directory;
loc = rfind(path, "\\");
path = path[0 .. loc];
break;
default:
// add
path = join(path, s);
break;
}
}

// drive letter only
if(getDrive(path) == path)
path ~= "\\";

return path;

}

// utf8 -> sjis
private void execute(string text){

char* c = cast(char*)std.file.toMBSz(text);
char[] sjis;

for(int i=0; *c!=0x00; i++){
sjis.length = i+1;
sjis[i] = *c;
c++;
}

string com = cast(string)sjis;
system(com);
}

 引数1つの場合は、絶対パスに変換して返します。引数が2つ以上の場合は、最初の引数をコマンドと解釈して、以下に続くパスを絶対パスに変換して実行します。
 実際はこんな感じのバッチファイルを作成して利用しています。結構快適です。

toabs.bat

toabs.exe ContextMenu.exe %*

2007年12月2日日曜日

D言語でローマ字変換するの巻

 そもそも自作のコマンドプロンプトつくりたいと考えたのは、コマンドプロンプトだと全角半角のファイル名の入力がメンド臭かったから。「だったらファイル名に全角文字なんか入れなきゃいいじゃん。」とも思うのですが、仕事で送られてくるファイルは100%全角だし、やっぱり見やすいから自分でも日本語のファイル名にしてしまうんですよねぇ。
 なんで、migemo でファイル名を指定できたら、全角/半角の切替をしなくて済むから便利だな、って考えてプロンプトの自作を夢想するようになりました。

 でも、普段は日本語入力IMEはskkimeを利用してるので、プロンプトからまんまskk方式で入力できたら、もっと便利だなぁと最近気付きました。プロンプトの入力部分を自作するんであれば、それも可能です。「小文字で入力したら半角入力と判断、大文字で(頭文字を)入力したら全角変換できる」っていうイメージ。Windowsのファイル名は大文字小文字の区別がないから、それで充分使えるなぁ。

 という訳で、ローマ字入力するサンプルを作成。ローマ字入力すると平仮名変換するので、あとはSKKIMEの辞書ファイルをこれで読みにいけばいいのかな?

import std.stdio;
import std.windows.charset;

string[string] roma;

void main(){

init_roma();

string line;
string word;

while(true){

printf("word:");
line = readln();

if(line == "exit\n")
break;

word = convert_hira(line);

printf(toMBSz(word));
printf("\n");

}
}

string convert_hira(string line){

string word = "";
string key = "";
string* check;

foreach(c ; line){

key ~= c;

check = key in roma;

if(check !is null){
word ~= *check;
key = "";
}
}

if(key.length > 0)
word ~= key;

return word;
}

void init_roma(){
roma["a"] = "あ"; roma["i"] = "い"; roma["u"] = "う";
roma["e"] = "え"; roma["o"] = "お"; roma["ka"] = "か";
roma["ki"] = "き"; roma["ku"] = "く"; roma["ke"] = "け";
roma["ko"] = "こ"; roma["sa"] = "さ"; roma["si"] = "し";
roma["su"] = "す"; roma["se"] = "せ"; roma["so"] = "そ";
roma["ta"] = "た"; roma["ti"] = "ち"; roma["tu"] = "つ";
roma["te"] = "て"; roma["to"] = "と"; roma["na"] = "な";
roma["ni"] = "に"; roma["nu"] = "ぬ"; roma["ne"] = "ね";
roma["no"] = "の"; roma["ha"] = "は"; roma["hi"] = "ひ";
roma["hu"] = "ふ"; roma["he"] = "へ"; roma["ho"] = "ほ";
roma["ma"] = "ま"; roma["mi"] = "み"; roma["mu"] = "む";
roma["me"] = "め"; roma["mo"] = "も"; roma["ya"] = "や";
roma["yu"] = "ゆ"; roma["yo"] = "よ"; roma["ra"] = "ら";
roma["ri"] = "り"; roma["ru"] = "る"; roma["re"] = "れ";
roma["ro"] = "ろ"; roma["wa"] = "わ"; roma["wo"] = "を";
roma["nn"] = "ん";
roma["kya"] = "きゃ"; roma["kyu"] = "きゅ"; roma["kyo"] = "きょ";
roma["sha"] = "しゃ"; roma["shu"] = "しゅ"; roma["sho"] = "しょ";
roma["cha"] = "ちゃ"; roma["chu"] = "ちゅ"; roma["cho"] = "ちょ";
roma["nya"] = "にゃ"; roma["nyu"] = "にゅ"; roma["nyo"] = "にょ";
roma["hya"] = "ひゃ"; roma["hyu"] = "ひゅ"; roma["hyo"] = "ひょ";
roma["mya"] = "みゃ"; roma["myu"] = "みゅ"; roma["myo"] = "みょ";
roma["rya"] = "りゃ"; roma["ryu"] = "りゅ"; roma["ryo"] = "りょ";
roma["ga"] = "が"; roma["gi"] = "ぎ"; roma["gu"] = "ぐ";
roma["ge"] = "げ"; roma["go"] = "ご"; roma["gya"] = "ぎゃ";
roma["gyu"] = "ぎゅ"; roma["gyo"] = "ぎょ"; roma["za"] = "ざ";
roma["zi"] = "じ"; roma["zu"] = "ず"; roma["ze"] = "ぜ";
roma["zo"] = "ぞ"; roma["ja"] = "じゃ"; roma["ju"] = "じゅ";
roma["jo"] = "じょ"; roma["da"] = "だ"; roma["di"] = "ぢ";
roma["du"] = "づ"; roma["de"] = "で"; roma["do"] = "ど";
roma["ba"] = "ば"; roma["bi"] = "び"; roma["bu"] = "ぶ";
roma["be"] = "べ"; roma["bo"] = "ぼ"; roma["bya"] = "びゃ";
roma["byu"] = "びゅ"; roma["byo"] = "ぴょ"; roma["pa"] = "ぱ";
roma["pi"] = "ぴ"; roma["pu"] = "ぷ"; roma["pe"] = "ぺ";
roma["po"] = "ぽ"; roma["pya"] = "ぴゃ"; roma["pyu"] = "ぴゅ";
roma["pyo"] = "ぴょ";
roma["ppa"] = "っぱ";
}


 サンプルなのでローマ変換の設定は途中まで。設定の中身を増やせば ACT とか AZIC にも対応できるはず。

D言語で自作のプロンプトをつくりたい(その2)

 前に自作のプロンプトをつくりたいと思ってサンプルだけつくったのですが、getcだと[tab]キーが取得できないことが判明。しかも[enter]キーを押した段階でしか文字列を取得して処理が走らないということで、それだと[tab]キー押して候補表示とかできないじゃん!

 案としては
  1. getch で1文字ずつ取得してカーソル制御は自前でなんとかする(BSキーの対応とか、カーソル移動とか)
  2. getc、getcharでなんとか[tab]キー取得できないの?
とか考えたのですが、調べてみても結局getcharはわからずじまいだったので、 getchで自分でカーソル制御を実装することにしました。

import std.stdio;
import std.process;
import std.c.stdio;

void main(){

int c;
string com;
bool loop = true;

printf(">");

while(loop){

c = getch();

switch(c){
case 13: // ret

if(com == "exit"){
// loop exit
loop = false;
} else {
// cmd execute
printf("\n");
system(com);
}
com.length = 0;
printf("\n");
printf(">");
break;

default:
if(c < 0x100){
// hankaku
com ~= c;
} else {
// zenkaku
com ~= c & 0xff;
com ~= c >> 8;
}
printf("%s",&c);
}
}
}



 最初、getchで全角文字が取得できなくて途方に暮れかけたのですが、戻り値を char で受けてたのが原因でした。int型でもらえば全然大丈夫。考えてみれば当たり前か。

 これからカーソルの操作について処理を増やしていく予定。あとgetchだと[DELETE]キーの取得ができないのは何故?Ctrl+Dで代用する予定だからいいのですが、どれも帯に短しタスキに長し。。。

2007年11月26日月曜日

D言語で自作のプロンプトをつくりたい

 D言語でプロンプトを使い易くするためのツールを自作しています。なんでD言語かっていうと、それはなんとなくで。なんかD言語ってインディーズな雰囲気がして好きなのです。あと、プログラム歴は何気にVBが一番長いので、ガーベージコレクションがないと不安なのです。(freeとかmallocってなに?)
 フリーのコンパイラだと、gccとかbccとかありますが、gccはwindowsだと使いずらそうだし、bccはダウンロード時に登録が必要なのがあまり好きじゃない。

 コマンドプロンプトだと標準入力で手軽にツールを作成できるのもいいところです。だいたいプログラムを勉強すると始めにやるのは"Hello! world!!"だと思うのですが、普通にプログラムしてる人ってprintf(標準出力)なんてほとんど使わないのでは?

 最終的には migemoが利用できるプロンプトを自作したいな、なんて考えているのですが、地道にちまちまやっていこうと思っています。とりあえず第一歩として、プロンプトの骨格を以下にメモメモ。

import std.stdio;
import std.process;
import std.c.stdio;

void main(){

char c;
string com;
bool loop = true;

writef(">");

while(loop){

c = getc(stdin);

switch(c){
case 0x0a: // ret
if(com == "exit"){
// loop exit
loop = false;
} else {
// cmd execute
system(com);
}
com.length = 0;
writef(">");
break;

default:
com ~= c;
}
}
}

 D言語だとデフォルトがutf8で、Shift-JISが使えないので、標準ライブラリの readln とかが使えません。んで色々試行錯誤した結果上記な感じになりました。getcの仕組みとか、あんまりよく調べてはないけど、 たぶんそんなに的外れでもないと思ってます。switch文の中をいじれば、Ctrl+P,Nで履歴表示や、TABでのキーワード補完とかも作れそう。
 (でもホントは GNU readline が使いたい~。けどwindowsでの使い方がわからない~)

2007年11月9日金曜日

コマンドプロンプトで2画面ファイラ(風)


 今までファイラは主に「あふ(Afx)」を利用していました。キーボードだけで操作ができたり(というかマウスは利用できない)とか、DLLさえあれば、圧縮ファイルをそのまま開けたりとか、もうすごい便利。
 特に、もう定番の画面構成ですが、2画面あるっていうのは便利でした。


 パソコン使っててのファイル操作で一番利用するのって、コピーとか移動だと思うのですが、Windows標準のエクスプローラーだと、移動元、移動先のフォルダが一度に指定できないんですよね。
 2枚立ち上げればいいんでしょうが、それもメンドくさい。

 あふ使う場合は、
  1. 移動元のフォルダを左に開いて、
  2. TABキーで操作を右に切り変えて、
  3. 移動先のフォルダを右に開いて、
  4. コピー処理
なんて感じでコピーします。


 という訳で、コマンドプロンプトでも同じ操作がしたい!と思いバッチファイルを作成しました。

mark.bat

@echo off
if "%1"=="" (
set mark=%cd%
echo Mark : %cd%
prompt $_--------------------$_$d$s$g$s$c$s%cd%$s$f$_$s$s$p$_$$s
) else if "%1"=="1" (
set mark1=%cd%
echo Mark1 : %cd%
) else if "%1"=="2" (
set mark2=%cd%
echo Mark2 : %cd%
) else if "%1"=="3" (
set mark3=%cd%
echo Mark3 : %cd%
) else (
set mark=%1
echo Mark : %1
prompt $_--------------------$_$d$s$g$s$c$s%1$s$f$_$s$s$p$_$$s
)


ch.bat

@echo off
set markswap=%mark%
set markswap1=%mark1%
set markswap2=%mark2%
set markswap3=%mark3%

if "%1"=="" (
set mark=%cd%
cd /D %markswap%
echo swap : %markswap%
prompt $_--------------------$_$d$s$g$s$c$s%cd%$s$f$_$s$s$p$_$$s
) else if "%1"=="1" (
set mark1=%cd%
cd /D %markswap1%
echo swap : %markswap1%
) else if "%1"=="2" (
set mark2=%cd%
cd /D %markswap2%
echo swap : %markswap1%
) else if "%1"=="3" (
set mark3=%cd%
cd /D %markswap3%
echo swap : %markswap1%
)

 mark.bat でコマンドプロンプトでそのとき開いているパスを環境変数に設定します。履歴として過去3回分保存します。
 ch.bat で環境変数に保存しているパスと開いているパスを交換します。履歴パスに移動したい場合は、「ch 2」とか入力します。
 prompt は好みです。


 コピーする際の実際の操作は、
  1. コマンドプロンプトで移動元のAフォルダを開く。
  2. markコマンドで、移動元のAフォルダを設定。
  3. 移動先のBフォルダを開く。
  4. chコマンドで、A⇔Bを交換。Aフォルダに移動。
  5. コピーする。cp コピーするファイル %mark%
みたいな感じです。
 ch 連打で、A⇔B が自由に切り変わるので、コピーだけでなくて普通に作業するときもイイ感じです。
 2画面ファイラとは違うけれども、TABキーで左右を切り変えるのと、chで切り変えるのが似てるので、気持ち的にはあふの操作っぽいと思っているのですが、どうでしょう。




2007年11月6日火曜日

dir じゃなくって、つい ls って入力してしまう。

コマンドプロンプトいじるキッカケになったのが、
Linux の bash なので、
ついファイル構成を確認するのに、lsって入れてしまいます。

そもそも ファイル確認 って一番よく入力するコマンドだと思うんだけど、
l と s がホームポジションの右薬指→左薬指 って入力し易すぎます。
毎回毎回、dir なんて3ストロークも打ってられません。

unix のシステムってひょっとしてここまで考えて作られてるのでしょうか?
深いです。。。

ということで、
NT版UNIX-like tools」。
使わせてもらってます。
Windowsのコマンドプロンプトで、
ls とか cp とか mv とか rm とか使えるようになるコマンド集です。
あと何気に head とか tail も便利。

もう今後一生使い続けたい。
Vista とかにも対応してるんでしょうか?
開発者様にはなるべく長~い対応を
よろしくお願いしたいものです。

2007年11月2日金曜日

CUI が好きです。

CUIが好きなのです。
「GUIなんて飾りです!えらい人にはそれがわからんのです!!」
なんて言葉がありますが、まったくその通りだと考えてます。
えらい人にはわからんのですよ。。。

PCの操作では基本的にマウスは使わない方が効率的に利用できるはず。
もともとGUIってのはPCの不得手な人が、特別な知識なしで利用できるように、
というためのモンだと思ってるので、
初心者を卒業できる人はキーボードのみで利用するべきです。

なんて思いたち、なんとなく、
これからはコマンドプロンプトでPCの操作をすることにしました。
もともとファイラはAfx、fenrir、ブラウザはFirefoxのVimperatorを利用してるので、
マウスを使う機会もほとんどないのですが、
今後はさらに徹底してコマンドプロンプトで行こう!なんて。

とは言うものの、
やっぱりプロンプトだけでは使いづらいので、
いろんなツールをつくろうと考えつきました。
Rubyの松本さんも言っているように、
Geekは不満を言わずに、必要なものは自分でつくる!!

そんなこんなで自分で作成したモンをネット上で置いておけるように、
ブログ始めてみました。
これで、職場と自宅で同じ環境を再現できる♪

ちなみに環境はWindowsだったりする。
Linux はshell が使い易くていいなぁぁぁ。。。