cshでは,cdコマンドは組み込みコマンドである.よって,execveでは実行できない.これを実装してみた.
cdの実装には,chdirシステムコールを利用する.以下に構文規則を示す.
top : expr {
command($1);
free_node($1);
}
;
expr:
~省略~
| cmd {$$ = new_node('w',$1->value,NULL,NULL);}
| cmd {arg_count=0;} file
{$$ = new_node('w',$1->value,$3,NULL);} // cd
~省略~
cdの構文規則は上のようになる.cmd(cd)の引数は,file一つか,ないものとなる.
以下にcdが実行される関数commandを示す.
void
command(d)
node *d;
{
~省略~
case 2: // cd
if( d->left != NULL ){ // 引数があれば
if( d->left->value[0]== '~' ){ // '~'の展開
homelen = strlen(getenv("HOME"));
filelen = strlen(d->left->value);
// チルダを消す(上書きする)ので,終端文字のために要素数を+1しなくて良い
path = (char *)calloc(homelen+filelen,sizeof(char));
if(path == NULL){
perror(path);
}
strcpy(path,getenv("HOME"));
// d->left->value+1 で'~'より後の文字列を連結
strncat(path,d->left->value+1,filelen);
if (chdir(path) == -1){
perror(path);
}
free(path);
}else if( chdir(d->left->value) == -1){
perror(d->left->value);
}
}else{ // 引数がなければhomeに移動
if( chdir(getenv("HOME") ) == -1){
perror(getenv("HOME"));
}
}
break;
~省略~
}
d->leftがNULLということは,引数がないということである.このときは,else文が実行され,
getenv関数で環境変数HOMEを取得して,HOMEに移動するようにしている.d->leftがNULLじゃ
ない場合は,引数にディレクトリ名がきているはずなので,そのディレクトリに移動するようにして
いる.また,引数の先頭がチルダなら,チルダをHOMEに展開する.
実行結果
[nw0409:unixlab2/leoinfo4/ch_dir] j04009% ./my-shell
j04009 % pwd
/Users/j04009/Documents/u-ryukyu/2006-Kouki/unixlab2/leoinfo4/ch_dir
j04009 % cd ../
j04009 % pwd
/Users/j04009/Documents/u-ryukyu/2006-Kouki/unixlab2/leoinfo4
j04009 % ls -l
total 152
-rw-r--r-- 1 j04009 j04009 93 Jan 14 17:35 Makefile
drwxr-xr-x 16 j04009 j04009 544 Jan 16 02:40 ch_dir
drwxr-xr-x 14 j04009 j04009 476 Jan 14 20:08 levelX
-rwxr-xr-x 1 j04009 j04009 34680 Jan 14 17:36 my-shell
-rw-r--r-- 1 j04009 j04009 21644 Jan 14 17:36 shell.c
-rwxrwxrwx 1 j04009 j04009 10436 Jan 14 00:25 shell.y
drwxr-xr-x 7 j04009 j04009 238 Jan 16 02:42 tex
j04009 % cd shell.c
shell.c: Not a directory
j04009 % cd
j04009 % pwd
/Users/j04009
j04009 % cd Documents/u-ryukyu/2006-Kouki/unixlab2/leoinfo4/ch_dir
j04009 % pwd
/Users/j04009/Documents/u-ryukyu/2006-Kouki/unixlab2/leoinfo4/ch_dir
j04009 % cd ~/
j04009 % pwd
/Users/j04009
j04009 % exit
ディレクトリの移動ができていることが確認できる.引数がディレクトリでない場合も,ちゃんと
エラーが出ている.また,チルダを使ったディレクトリの移動もできていることが確認できる.